blob: a273120d9f9b9d9c69b517dce96125ce2a695c15 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass56ee85e2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070022
Simon Glass386c63c2022-01-09 20:13:50 -070023from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070029from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass4583c002023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass4f443042016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass6ad24522022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glassc6c10e72019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
Sughosh Ganub6176112023-08-22 23:09:59 +053051EFI_CAPSULE_DATA = b'efi'
Simon Glassc6c10e72019-05-17 22:00:46 -060052U_BOOT_DTB_DATA = b'udtb'
53U_BOOT_SPL_DTB_DATA = b'spldtb'
54U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass6ad24522022-02-28 07:16:54 -070055U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glassc6c10e72019-05-17 22:00:46 -060056X86_START16_DATA = b'start16'
57X86_START16_SPL_DATA = b'start16spl'
58X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060059X86_RESET16_DATA = b'reset16'
60X86_RESET16_SPL_DATA = b'reset16spl'
61X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060062PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
63U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
64U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
65U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass6ad24522022-02-28 07:16:54 -070066U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak21353312022-02-08 01:08:04 +030067U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
68U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
69U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glassc6c10e72019-05-17 22:00:46 -060070FSP_DATA = b'fsp'
71CMC_DATA = b'cmc'
72VBT_DATA = b'vbt'
73MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060074TEXT_DATA = 'text'
75TEXT_DATA2 = 'text2'
76TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060077CROS_EC_RW_DATA = b'ecrw'
78GBB_DATA = b'gbbd'
79BMPBLK_DATA = b'bmp'
80VBLOCK_DATA = b'vblk'
81FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
82 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060083COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060084COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060085REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060086FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060087FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060088FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060089ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020090TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis23d2ef92023-12-05 15:12:18 +053091TI_DM_DATA = b'tidmtidm'
Simon Glass75989722021-11-23 21:08:59 -070092ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080093OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050094SCP_DATA = b'scp'
Jonas Karlman05b978b2023-02-25 19:01:33 +000095ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glass6cf99532020-09-01 05:13:59 -060096TEST_FDT1_DATA = b'fdt1'
97TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060098ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke289e6002023-07-17 09:05:54 +020099ENCRYPTED_IV_DATA = b'123456'
100ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesb1c50932022-03-28 22:57:04 +0200101PRE_LOAD_MAGIC = b'UBSH'
102PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
103PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530104TI_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 +0530105TI_UNSECURE_DATA = b'unsecuredata'
Simon Glass6cf99532020-09-01 05:13:59 -0600106
107# Subdirectory of the input dir to use to put test FDTs
108TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600109
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600110# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600111EXTRACT_DTB_SIZE = 0x3c9
112
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600113# Properties expected to be in the device tree when update_dtb is used
114BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
115
Simon Glass12bb1a92019-07-20 12:23:51 -0600116# Extra properties expected to be in the device tree when allow-repack is used
117REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
118
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200119# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200120COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700121
Simon Glass2f80c5e2023-01-07 14:07:14 -0700122TEE_ADDR = 0x5678
123
Sughosh Ganub6176112023-08-22 23:09:59 +0530124# Firmware Management Protocol(FMP) GUID
Sughosh Ganu809f28e2023-10-10 14:40:57 +0530125FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganub6176112023-08-22 23:09:59 +0530126# Image GUID specified in the DTS
Sughosh Ganu809f28e2023-10-10 14:40:57 +0530127CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
128# Windows cert GUID
129WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu74aae502023-10-10 14:40:59 +0530130# Empty capsule GUIDs
131EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
132EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganub6176112023-08-22 23:09:59 +0530133
Simon Glass4f443042016-11-25 20:15:52 -0700134class TestFunctional(unittest.TestCase):
135 """Functional tests for binman
136
137 Most of these use a sample .dts file to build an image and then check
138 that it looks correct. The sample files are in the test/ subdirectory
139 and are numbered.
140
141 For each entry type a very small test file is created using fixed
142 string contents. This makes it easy to test that things look right, and
143 debug problems.
144
145 In some cases a 'real' file must be used - these are also supplied in
146 the test/ diurectory.
147 """
148 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600149 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700150 global entry
Simon Glass16287932020-04-17 18:09:03 -0600151 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700152
Simon Glass4f443042016-11-25 20:15:52 -0700153 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600154 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
155 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700156
157 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600158 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700159
160 # Create some test files
161 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
162 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
163 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600164 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700165 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700166 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700167 TestFunctional._MakeInputFile('me.bin', ME_DATA)
168 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600169 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600170
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530171 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600172
Simon Glass5e239182019-08-24 07:22:49 -0600173 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
174 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700175 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600176 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600177 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600178
179 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
180 X86_RESET16_DATA)
181 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
182 X86_RESET16_SPL_DATA)
183 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
184 X86_RESET16_TPL_DATA)
185
Simon Glass4f443042016-11-25 20:15:52 -0700186 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700187 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
188 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600189 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
190 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700191 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
192 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700193 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
194 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700195 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700196 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600197 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600198 TestFunctional._MakeInputDir('devkeys')
199 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600200 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600201 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600202 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600203 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700204
Simon Glass53e22bf2019-08-24 07:22:53 -0600205 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
206 elf_test.BuildElfTestFiles(cls._elf_testdir)
207
Simon Glasse0ff8552016-11-25 20:15:53 -0700208 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600209 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700210 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700211
212 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600213 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700214
Simon Glassb986b3b2019-08-24 07:22:43 -0600215 shutil.copytree(cls.TestFile('files'),
216 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600217
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530218 shutil.copytree(cls.TestFile('yaml'),
219 os.path.join(cls._indir, 'yaml'))
220
Simon Glass83d73c22018-09-14 04:57:26 -0600221 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600222 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600223 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200224 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis23d2ef92023-12-05 15:12:18 +0530225 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700226 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800227 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500228 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman05b978b2023-02-25 19:01:33 +0000229 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis78144822023-07-22 00:14:25 +0530230 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganub6176112023-08-22 23:09:59 +0530231 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600232
Simon Glass6cf99532020-09-01 05:13:59 -0600233 # Add a few .dtb files for testing
234 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
235 TEST_FDT1_DATA)
236 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
237 TEST_FDT2_DATA)
238
Simon Glassfb91d562020-09-06 10:35:33 -0600239 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
240
Simon Glass40c8bdd2022-03-05 20:19:12 -0700241 # ELF file with two sections in different parts of memory, used for both
242 # ATF and OP_TEE
243 TestFunctional._MakeInputFile('bl31.elf',
244 tools.read_file(cls.ElfTestFile('elf_sections')))
245 TestFunctional._MakeInputFile('tee.elf',
246 tools.read_file(cls.ElfTestFile('elf_sections')))
247
Simon Glass2f80c5e2023-01-07 14:07:14 -0700248 # Newer OP_TEE file in v1 binary format
249 cls.make_tee_bin('tee.bin')
250
Christian Taedcke289e6002023-07-17 09:05:54 +0200251 # test files for encrypted tests
252 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
253 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
254
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200255 cls.comp_bintools = {}
256 for name in COMP_BINTOOLS:
257 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600258
Simon Glass4f443042016-11-25 20:15:52 -0700259 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600260 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700261 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600262 if cls.preserve_indir:
263 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600264 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600265 if cls._indir:
266 shutil.rmtree(cls._indir)
267 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700268
Simon Glassd5164a72019-07-08 13:18:49 -0600269 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600270 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600271 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600272 """Accept arguments controlling test execution
273
274 Args:
275 preserve_indir: Preserve the shared input directory used by all
276 tests in this class.
277 preserve_outdir: Preserve the output directories used by tests. Each
278 test has its own, so this is normally only useful when running a
279 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600280 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600281 """
282 cls.preserve_indir = preserve_indir
283 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600284 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600285 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600286
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200287 def _CheckBintool(self, bintool):
288 if not bintool.is_present():
289 self.skipTest('%s not available' % bintool.name)
290
Simon Glassac62fba2019-07-08 13:18:53 -0600291 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200292 bintool = self.comp_bintools['lz4']
293 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600294
Simon Glassbf574f12019-07-20 12:24:09 -0600295 def _CleanupOutputDir(self):
296 """Remove the temporary output directory"""
297 if self.preserve_outdirs:
298 print('Preserving output dir: %s' % tools.outdir)
299 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700300 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600301
Simon Glass4f443042016-11-25 20:15:52 -0700302 def setUp(self):
303 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700304 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700305 command.test_result = None
306
307 def tearDown(self):
308 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600309 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700310
Simon Glassf86a7362019-07-20 12:24:10 -0600311 def _SetupImageInTmpdir(self):
312 """Set up the output image in a new temporary directory
313
314 This is used when an image has been generated in the output directory,
315 but we want to run binman again. This will create a new output
316 directory and fail to delete the original one.
317
318 This creates a new temporary directory, copies the image to it (with a
319 new name) and removes the old output directory.
320
321 Returns:
322 Tuple:
323 Temporary directory to use
324 New image filename
325 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700326 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600327 tmpdir = tempfile.mkdtemp(prefix='binman.')
328 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700329 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600330 self._CleanupOutputDir()
331 return tmpdir, updated_fname
332
Simon Glassb8ef5b62018-07-17 13:25:48 -0600333 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600334 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600335 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
336 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
337 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700338 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600339
Simon Glass4f443042016-11-25 20:15:52 -0700340 def _RunBinman(self, *args, **kwargs):
341 """Run binman using the command line
342
343 Args:
344 Arguments to pass, as a list of strings
345 kwargs: Arguments to pass to Command.RunPipe()
346 """
Simon Glassd9800692022-01-29 14:14:05 -0700347 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700348 capture=True, capture_stderr=True, raise_on_error=False)
349 if result.return_code and kwargs.get('raise_on_error', True):
350 raise Exception("Error running '%s': %s" % (' '.join(args),
351 result.stdout + result.stderr))
352 return result
353
Simon Glass53cd5d92019-07-08 14:25:29 -0600354 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700355 """Run binman using directly (in the same process)
356
357 Args:
358 Arguments to pass, as a list of strings
359 Returns:
360 Return value (0 for success)
361 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600362 argv = list(argv)
363 args = cmdline.ParseArgs(argv)
364 args.pager = 'binman-invalid-pager'
365 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700366
367 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600368 # args.verbosity = tout.DEBUG
369 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700370
Simon Glass53af22a2018-07-17 13:25:32 -0600371 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600372 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300373 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100374 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700375 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis15432ea2023-07-22 00:14:44 +0530376 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass4f443042016-11-25 20:15:52 -0700377 """Run binman with a given test file
378
379 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600380 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600381 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600382 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600383 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600384 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600385 entry_args: Dict of entry args to supply to binman
386 key: arg name
387 value: value of that arg
388 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600389 use_real_dtb: True to use the test file as the contents of
390 the u-boot-dtb entry. Normally this is not needed and the
391 test contents (the U_BOOT_DTB_DATA string) can be used.
392 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300393 use_expanded: True to use expanded entries where available, e.g.
394 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600395 verbosity: Verbosity level to use (0-3, None=don't set it)
396 allow_missing: Set the '--allow-missing' flag so that missing
397 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100398 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600399 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600400 threads: Number of threads to use (None for default, 0 for
401 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600402 test_section_timeout: True to force the first time to timeout, as
403 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600404 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700405 force_missing_tools (str): comma-separated list of bintools to
406 regard as missing
Andrew Davis15432ea2023-07-22 00:14:44 +0530407 output_dir: Specific output directory to use for image using -O
Simon Glass7115f002021-11-03 21:09:17 -0600408
409 Returns:
410 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700411 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600412 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700413 if debug:
414 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600415 if verbosity is not None:
416 args.append('-v%d' % verbosity)
417 elif self.verbosity:
418 args.append('-v%d' % self.verbosity)
419 if self.toolpath:
420 for path in self.toolpath:
421 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600422 if threads is not None:
423 args.append('-T%d' % threads)
424 if test_section_timeout:
425 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600426 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600427 if map:
428 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600429 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600430 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600431 if not use_real_dtb:
432 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300433 if not use_expanded:
434 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600435 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600436 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600437 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600438 if allow_missing:
439 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700440 if ignore_missing:
441 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100442 if allow_fake_blobs:
443 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700444 if force_missing_bintools:
445 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600446 if update_fdt_in_elf:
447 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600448 if images:
449 for image in images:
450 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600451 if extra_indirs:
452 for indir in extra_indirs:
453 args += ['-I', indir]
Andrew Davis15432ea2023-07-22 00:14:44 +0530454 if output_dir:
455 args += ['-O', output_dir]
Simon Glass7fe91732017-11-13 18:55:00 -0700456 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700457
458 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700459 """Set up a new test device-tree file
460
461 The given file is compiled and set up as the device tree to be used
462 for ths test.
463
464 Args:
465 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600466 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700467
468 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600469 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700470 """
Simon Glassa004f292019-07-20 12:23:49 -0600471 tmpdir = tempfile.mkdtemp(prefix='binmant.')
472 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600473 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700474 data = fd.read()
475 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600476 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600477 return data
Simon Glass4f443042016-11-25 20:15:52 -0700478
Simon Glass6ad24522022-02-28 07:16:54 -0700479 def _GetDtbContentsForSpls(self, dtb_data, name):
480 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glass6ed45ba2018-09-14 04:57:24 -0600481
482 For testing we don't actually have different versions of the DTB. With
483 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
484 we don't normally have any unwanted nodes.
485
486 We still want the DTBs for SPL and TPL to be different though, since
487 otherwise it is confusing to know which one we are looking at. So add
488 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600489
490 Args:
491 dtb_data: dtb data to modify (this should be a value devicetree)
492 name: Name of a new property to add
493
494 Returns:
495 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600496 """
497 dtb = fdt.Fdt.FromData(dtb_data)
498 dtb.Scan()
499 dtb.GetNode('/binman').AddZeroProp(name)
500 dtb.Sync(auto_resize=True)
501 dtb.Pack()
502 return dtb.GetContents()
503
Simon Glass63aeaeb2021-03-18 20:25:05 +1300504 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
505 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600506 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700507 """Run binman and return the resulting image
508
509 This runs binman with a given test file and then reads the resulting
510 output file. It is a shortcut function since most tests need to do
511 these steps.
512
513 Raises an assertion failure if binman returns a non-zero exit code.
514
515 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600516 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700517 use_real_dtb: True to use the test file as the contents of
518 the u-boot-dtb entry. Normally this is not needed and the
519 test contents (the U_BOOT_DTB_DATA string) can be used.
520 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300521 use_expanded: True to use expanded entries where available, e.g.
522 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600523 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600524 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600525 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600526 entry_args: Dict of entry args to supply to binman
527 key: arg name
528 value: value of that arg
529 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
530 function. If reset_dtbs is True, then the original test dtb
531 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600532 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600533 threads: Number of threads to use (None for default, 0 for
534 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700535
536 Returns:
537 Tuple:
538 Resulting image contents
539 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600540 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600541 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700542 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700543 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700544 # Use the compiled test file as the u-boot-dtb input
545 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700546 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600547
548 # For testing purposes, make a copy of the DT for SPL and TPL. Add
549 # a node indicating which it is, so aid verification.
Simon Glass6ad24522022-02-28 07:16:54 -0700550 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -0600551 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
552 outfile = os.path.join(self._indir, dtb_fname)
553 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass6ad24522022-02-28 07:16:54 -0700554 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700555
556 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600557 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600558 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600559 use_expanded=use_expanded, extra_indirs=extra_indirs,
560 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700561 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700562 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700563
564 # Find the (only) image, read it and return its contents
565 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700566 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600567 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600568 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700569 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600570 with open(map_fname) as fd:
571 map_data = fd.read()
572 else:
573 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600574 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600575 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700576 finally:
577 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600578 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600579 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700580
Simon Glass3c081312019-07-08 14:25:26 -0600581 def _DoReadFileRealDtb(self, fname):
582 """Run binman with a real .dtb file and return the resulting data
583
584 Args:
585 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
586
587 Returns:
588 Resulting image contents
589 """
590 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
591
Simon Glasse0ff8552016-11-25 20:15:53 -0700592 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600593 """Helper function which discards the device-tree binary
594
595 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600596 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600597 use_real_dtb: True to use the test file as the contents of
598 the u-boot-dtb entry. Normally this is not needed and the
599 test contents (the U_BOOT_DTB_DATA string) can be used.
600 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600601
602 Returns:
603 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600604 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700605 return self._DoReadFileDtb(fname, use_real_dtb)[0]
606
Simon Glass4f443042016-11-25 20:15:52 -0700607 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600608 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700609 """Create a new test input file, creating directories as needed
610
611 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600612 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700613 contents: File contents to write in to the file
614 Returns:
615 Full pathname of file created
616 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600617 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700618 dirname = os.path.dirname(pathname)
619 if dirname and not os.path.exists(dirname):
620 os.makedirs(dirname)
621 with open(pathname, 'wb') as fd:
622 fd.write(contents)
623 return pathname
624
625 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600626 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600627 """Create a new test input directory, creating directories as needed
628
629 Args:
630 dirname: Directory name to create
631
632 Returns:
633 Full pathname of directory created
634 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600635 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600636 if not os.path.exists(pathname):
637 os.makedirs(pathname)
638 return pathname
639
640 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600641 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600642 """Set up an ELF file with a '_dt_ucode_base_size' symbol
643
644 Args:
645 Filename of ELF file to use as SPL
646 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600647 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700648 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600649
650 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600651 def _SetupTplElf(cls, src_fname='bss_data'):
652 """Set up an ELF file with a '_dt_ucode_base_size' symbol
653
654 Args:
655 Filename of ELF file to use as TPL
656 """
657 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700658 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600659
660 @classmethod
Simon Glass6ad24522022-02-28 07:16:54 -0700661 def _SetupVplElf(cls, src_fname='bss_data'):
662 """Set up an ELF file with a '_dt_ucode_base_size' symbol
663
664 Args:
665 Filename of ELF file to use as VPL
666 """
667 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
668 tools.read_file(cls.ElfTestFile(src_fname)))
669
670 @classmethod
Lukas Funke8c1fbd12023-07-18 13:53:13 +0200671 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
672 """Set up an ELF file with a '_dt_ucode_base_size' symbol
673
674 Args:
675 Filename of ELF file to use as VPL
676 """
677 TestFunctional._MakeInputFile('pmu-firmware.elf',
678 tools.read_file(cls.ElfTestFile(src_fname)))
679
680 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600681 def _SetupDescriptor(cls):
682 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
683 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
684
685 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600686 def TestFile(cls, fname):
687 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700688
Simon Glass53e22bf2019-08-24 07:22:53 -0600689 @classmethod
690 def ElfTestFile(cls, fname):
691 return os.path.join(cls._elf_testdir, fname)
692
Simon Glass2f80c5e2023-01-07 14:07:14 -0700693 @classmethod
694 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
695 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
696 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
697 dummy, paged_sz) + U_BOOT_DATA
698 data += extra_data
699 TestFunctional._MakeInputFile(fname, data)
700
Simon Glass4f443042016-11-25 20:15:52 -0700701 def AssertInList(self, grep_list, target):
702 """Assert that at least one of a list of things is in a target
703
704 Args:
705 grep_list: List of strings to check
706 target: Target string
707 """
708 for grep in grep_list:
709 if grep in target:
710 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600711 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700712
713 def CheckNoGaps(self, entries):
714 """Check that all entries fit together without gaps
715
716 Args:
717 entries: List of entries to check
718 """
Simon Glass3ab95982018-08-01 15:22:37 -0600719 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700720 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600721 self.assertEqual(offset, entry.offset)
722 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700723
Simon Glasse0ff8552016-11-25 20:15:53 -0700724 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600725 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700726
727 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600728 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700729
730 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600731 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700732 """
733 return struct.unpack('>L', dtb[4:8])[0]
734
Simon Glass086cec92019-07-08 14:25:27 -0600735 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600736 def AddNode(node, path):
737 if node.name != '/':
738 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600739 for prop in node.props.values():
740 if prop.name in prop_names:
741 prop_path = path + ':' + prop.name
742 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
743 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600744 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600745 AddNode(subnode, path)
746
747 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600748 AddNode(dtb.GetRoot(), '')
749 return tree
750
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +0000751 def _CheckSign(self, fit, key):
752 try:
753 tools.run('fit_check_sign', '-k', key, '-f', fit)
754 except:
755 self.fail('Expected signed FIT container')
756 return False
757 return True
758
Simon Glass4f443042016-11-25 20:15:52 -0700759 def testRun(self):
760 """Test a basic run with valid args"""
761 result = self._RunBinman('-h')
762
763 def testFullHelp(self):
764 """Test that the full help is displayed with -H"""
765 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300766 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500767 # Remove possible extraneous strings
768 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
769 gothelp = result.stdout.replace(extra, '')
770 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700771 self.assertEqual(0, len(result.stderr))
772 self.assertEqual(0, result.return_code)
773
774 def testFullHelpInternal(self):
775 """Test that the full help is displayed with -H"""
776 try:
777 command.test_result = command.CommandResult()
778 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300779 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700780 finally:
781 command.test_result = None
782
783 def testHelp(self):
784 """Test that the basic help is displayed with -h"""
785 result = self._RunBinman('-h')
786 self.assertTrue(len(result.stdout) > 200)
787 self.assertEqual(0, len(result.stderr))
788 self.assertEqual(0, result.return_code)
789
Simon Glass4f443042016-11-25 20:15:52 -0700790 def testBoard(self):
791 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600792 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700793 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300794 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700795 self.assertEqual(0, result)
796
797 def testNeedBoard(self):
798 """Test that we get an error when no board ius supplied"""
799 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600800 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700801 self.assertIn("Must provide a board to process (use -b <board>)",
802 str(e.exception))
803
804 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600805 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700806 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600807 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700808 # We get one error from libfdt, and a different one from fdtget.
809 self.AssertInList(["Couldn't open blob from 'missing_file'",
810 'No such file or directory'], str(e.exception))
811
812 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600813 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700814
815 Since this is a source file it should be compiled and the error
816 will come from the device-tree compiler (dtc).
817 """
818 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600819 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700820 self.assertIn("FATAL ERROR: Unable to parse input tree",
821 str(e.exception))
822
823 def testMissingNode(self):
824 """Test that a device tree without a 'binman' node generates an error"""
825 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600826 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700827 self.assertIn("does not have a 'binman' node", str(e.exception))
828
829 def testEmpty(self):
830 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600831 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700832 self.assertEqual(0, len(result.stderr))
833 self.assertEqual(0, result.return_code)
834
835 def testInvalidEntry(self):
836 """Test that an invalid entry is flagged"""
837 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600838 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600839 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700840 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
841 "'/binman/not-a-valid-type'", str(e.exception))
842
843 def testSimple(self):
844 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600845 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700846 self.assertEqual(U_BOOT_DATA, data)
847
Simon Glass7fe91732017-11-13 18:55:00 -0700848 def testSimpleDebug(self):
849 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600850 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700851
Simon Glass4f443042016-11-25 20:15:52 -0700852 def testDual(self):
853 """Test that we can handle creating two images
854
855 This also tests image padding.
856 """
Simon Glass741f2d62018-10-01 12:22:30 -0600857 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700858 self.assertEqual(0, retcode)
859
860 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600861 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700862 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700863 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600864 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700865 data = fd.read()
866 self.assertEqual(U_BOOT_DATA, data)
867
868 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600869 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700870 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700871 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600872 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700873 data = fd.read()
874 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700875 self.assertEqual(tools.get_bytes(0, 3), data[:3])
876 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700877
878 def testBadAlign(self):
879 """Test that an invalid alignment value is detected"""
880 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600881 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700882 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
883 "of two", str(e.exception))
884
885 def testPackSimple(self):
886 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600887 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700888 self.assertEqual(0, retcode)
889 self.assertIn('image', control.images)
890 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600891 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700892 self.assertEqual(5, len(entries))
893
894 # First u-boot
895 self.assertIn('u-boot', entries)
896 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600897 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700898 self.assertEqual(len(U_BOOT_DATA), entry.size)
899
900 # Second u-boot, aligned to 16-byte boundary
901 self.assertIn('u-boot-align', entries)
902 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600903 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700904 self.assertEqual(len(U_BOOT_DATA), entry.size)
905
906 # Third u-boot, size 23 bytes
907 self.assertIn('u-boot-size', entries)
908 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600909 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700910 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
911 self.assertEqual(23, entry.size)
912
913 # Fourth u-boot, placed immediate after the above
914 self.assertIn('u-boot-next', entries)
915 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600916 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700917 self.assertEqual(len(U_BOOT_DATA), entry.size)
918
Simon Glass3ab95982018-08-01 15:22:37 -0600919 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700920 self.assertIn('u-boot-fixed', entries)
921 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600922 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700923 self.assertEqual(len(U_BOOT_DATA), entry.size)
924
Simon Glass8beb11e2019-07-08 14:25:47 -0600925 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700926
927 def testPackExtra(self):
928 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600929 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
930 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700931
Simon Glass4f443042016-11-25 20:15:52 -0700932 self.assertIn('image', control.images)
933 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600934 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600935 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700936
Samuel Hollandb01ae032023-01-21 17:25:16 -0600937 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700938 self.assertIn('u-boot', entries)
939 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600940 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700941 self.assertEqual(3, entry.pad_before)
942 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600943 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700944 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
945 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600946 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700947
948 # Second u-boot has an aligned size, but it has no effect
949 self.assertIn('u-boot-align-size-nop', entries)
950 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600951 self.assertEqual(pos, entry.offset)
952 self.assertEqual(len(U_BOOT_DATA), entry.size)
953 self.assertEqual(U_BOOT_DATA, entry.data)
954 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
955 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700956
957 # Third u-boot has an aligned size too
958 self.assertIn('u-boot-align-size', entries)
959 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600960 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700961 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600962 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700963 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600964 data[pos:pos + entry.size])
965 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700966
967 # Fourth u-boot has an aligned end
968 self.assertIn('u-boot-align-end', entries)
969 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600970 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700971 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600972 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700973 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600974 data[pos:pos + entry.size])
975 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700976
977 # Fifth u-boot immediately afterwards
978 self.assertIn('u-boot-align-both', entries)
979 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600980 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700981 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600982 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700983 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600984 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700985
Samuel Hollandb01ae032023-01-21 17:25:16 -0600986 # Sixth u-boot with both minimum size and aligned size
987 self.assertIn('u-boot-min-size', entries)
988 entry = entries['u-boot-min-size']
989 self.assertEqual(128, entry.offset)
990 self.assertEqual(32, entry.size)
991 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
992 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
993 data[pos:pos + entry.size])
994
Simon Glass4f443042016-11-25 20:15:52 -0700995 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600996 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700997
Simon Glass4eec34c2020-10-26 17:40:10 -0600998 dtb = fdt.Fdt(out_dtb_fname)
999 dtb.Scan()
1000 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1001 expected = {
1002 'image-pos': 0,
1003 'offset': 0,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001004 'size': 160,
Simon Glass4eec34c2020-10-26 17:40:10 -06001005
1006 'u-boot:image-pos': 0,
1007 'u-boot:offset': 0,
1008 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1009
1010 'u-boot-align-size-nop:image-pos': 12,
1011 'u-boot-align-size-nop:offset': 12,
1012 'u-boot-align-size-nop:size': 4,
1013
1014 'u-boot-align-size:image-pos': 16,
1015 'u-boot-align-size:offset': 16,
1016 'u-boot-align-size:size': 32,
1017
1018 'u-boot-align-end:image-pos': 48,
1019 'u-boot-align-end:offset': 48,
1020 'u-boot-align-end:size': 16,
1021
1022 'u-boot-align-both:image-pos': 64,
1023 'u-boot-align-both:offset': 64,
1024 'u-boot-align-both:size': 64,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001025
1026 'u-boot-min-size:image-pos': 128,
1027 'u-boot-min-size:offset': 128,
1028 'u-boot-min-size:size': 32,
Simon Glass4eec34c2020-10-26 17:40:10 -06001029 }
1030 self.assertEqual(expected, props)
1031
Simon Glass4f443042016-11-25 20:15:52 -07001032 def testPackAlignPowerOf2(self):
1033 """Test that invalid entry alignment is detected"""
1034 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001035 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001036 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1037 "of two", str(e.exception))
1038
1039 def testPackAlignSizePowerOf2(self):
1040 """Test that invalid entry size alignment is detected"""
1041 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001042 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001043 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1044 "power of two", str(e.exception))
1045
1046 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001047 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -07001048 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001049 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001050 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001051 "align 0x4 (4)", str(e.exception))
1052
1053 def testPackInvalidSizeAlign(self):
1054 """Test that invalid entry size alignment is detected"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001056 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001057 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1058 "align-size 0x4 (4)", str(e.exception))
1059
1060 def testPackOverlap(self):
1061 """Test that overlapping regions are detected"""
1062 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001063 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001064 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001065 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1066 str(e.exception))
1067
1068 def testPackEntryOverflow(self):
1069 """Test that entries that overflow their size are detected"""
1070 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001071 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001072 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1073 "but entry size is 0x3 (3)", str(e.exception))
1074
1075 def testPackImageOverflow(self):
1076 """Test that entries which overflow the image size are detected"""
1077 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001078 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001079 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -07001080 "size 0x3 (3)", str(e.exception))
1081
1082 def testPackImageSize(self):
1083 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -06001084 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001085 self.assertEqual(0, retcode)
1086 self.assertIn('image', control.images)
1087 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001088 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001089
1090 def testPackImageSizeAlign(self):
1091 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001092 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001093 self.assertEqual(0, retcode)
1094 self.assertIn('image', control.images)
1095 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001096 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001097
1098 def testPackInvalidImageAlign(self):
1099 """Test that invalid image alignment is detected"""
1100 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001101 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001102 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001103 "align-size 0x8 (8)", str(e.exception))
1104
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001105 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001106 """Test that invalid image alignment is detected"""
1107 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001108 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001109 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001110 "two", str(e.exception))
1111
1112 def testImagePadByte(self):
1113 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001114 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001115 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001116 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001117 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001118
1119 def testImageName(self):
1120 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001121 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001122 self.assertEqual(0, retcode)
1123 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001124 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001125 self.assertTrue(os.path.exists(fname))
1126
1127 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001128 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001129 self.assertTrue(os.path.exists(fname))
1130
1131 def testBlobFilename(self):
1132 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001133 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001134 self.assertEqual(BLOB_DATA, data)
1135
1136 def testPackSorted(self):
1137 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001138 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001139 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001140 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1141 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001142
Simon Glass3ab95982018-08-01 15:22:37 -06001143 def testPackZeroOffset(self):
1144 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001145 self._SetupSplElf()
Simon Glass4f443042016-11-25 20:15:52 -07001146 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001147 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001148 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001149 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1150 str(e.exception))
1151
1152 def testPackUbootDtb(self):
1153 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001154 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001155 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001156
1157 def testPackX86RomNoSize(self):
1158 """Test that the end-at-4gb property requires a size property"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001159 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001160 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001161 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001162 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001163 "using end-at-4gb", str(e.exception))
1164
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301165 def test4gbAndSkipAtStartTogether(self):
1166 """Test that the end-at-4gb and skip-at-size property can't be used
1167 together"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001168 self._SetupSplElf()
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301169 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001170 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001171 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301172 "'skip-at-start'", str(e.exception))
1173
Simon Glasse0ff8552016-11-25 20:15:53 -07001174 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001175 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001176 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001177 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001178 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001179 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1180 "is outside the section '/binman' starting at "
1181 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001182 str(e.exception))
1183
1184 def testPackX86Rom(self):
1185 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001186 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001187 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001188 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1189 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001190
1191 def testPackX86RomMeNoDesc(self):
1192 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001193 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001194 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001195 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001196 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001197 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1198 str(e.exception))
1199 finally:
1200 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001201
1202 def testPackX86RomBadDesc(self):
1203 """Test that the Intel requires a descriptor entry"""
1204 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001205 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001206 self.assertIn("Node '/binman/intel-me': No offset set with "
1207 "offset-unset: should another entry provide this correct "
1208 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001209
1210 def testPackX86RomMe(self):
1211 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001212 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001213 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001214 if data[:0x1000] != expected_desc:
1215 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001216 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1217
1218 def testPackVga(self):
1219 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001220 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001221 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1222
1223 def testPackStart16(self):
1224 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001225 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001226 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1227
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301228 def testPackPowerpcMpc85xxBootpgResetvec(self):
1229 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1230 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001231 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301232 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1233
Simon Glass736bb0a2018-07-06 10:27:17 -06001234 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001235 """Handle running a test for insertion of microcode
1236
1237 Args:
1238 dts_fname: Name of test .dts file
1239 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001240 ucode_second: True if the microsecond entry is second instead of
1241 third
Simon Glassadc57012018-07-06 10:27:16 -06001242
1243 Returns:
1244 Tuple:
1245 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001246 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001247 in the above (two 4-byte words)
1248 """
Simon Glass6b187df2017-11-12 21:52:27 -07001249 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001250
1251 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001252 if ucode_second:
1253 ucode_content = data[len(nodtb_data):]
1254 ucode_pos = len(nodtb_data)
1255 dtb_with_ucode = ucode_content[16:]
1256 fdt_len = self.GetFdtLen(dtb_with_ucode)
1257 else:
1258 dtb_with_ucode = data[len(nodtb_data):]
1259 fdt_len = self.GetFdtLen(dtb_with_ucode)
1260 ucode_content = dtb_with_ucode[fdt_len:]
1261 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001262 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001263 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001264 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001265 dtb = fdt.FdtScan(fname)
1266 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001267 self.assertTrue(ucode)
1268 for node in ucode.subnodes:
1269 self.assertFalse(node.props.get('data'))
1270
Simon Glasse0ff8552016-11-25 20:15:53 -07001271 # Check that the microcode appears immediately after the Fdt
1272 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001273 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001274 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1275 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001276 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001277
1278 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001279 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001280 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1281 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001282 u_boot = data[:len(nodtb_data)]
1283 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001284
1285 def testPackUbootMicrocode(self):
1286 """Test that x86 microcode can be handled correctly
1287
1288 We expect to see the following in the image, in order:
1289 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1290 place
1291 u-boot.dtb with the microcode removed
1292 the microcode
1293 """
Simon Glass741f2d62018-10-01 12:22:30 -06001294 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001295 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001296 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1297 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001298
Simon Glass160a7662017-05-27 07:38:26 -06001299 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001300 """Test that x86 microcode can be handled correctly
1301
1302 We expect to see the following in the image, in order:
1303 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1304 place
1305 u-boot.dtb with the microcode
1306 an empty microcode region
1307 """
1308 # We need the libfdt library to run this test since only that allows
1309 # finding the offset of a property. This is required by
1310 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001311 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001312
1313 second = data[len(U_BOOT_NODTB_DATA):]
1314
1315 fdt_len = self.GetFdtLen(second)
1316 third = second[fdt_len:]
1317 second = second[:fdt_len]
1318
Simon Glass160a7662017-05-27 07:38:26 -06001319 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1320 self.assertIn(ucode_data, second)
1321 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001322
Simon Glass160a7662017-05-27 07:38:26 -06001323 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001324 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001325 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1326 len(ucode_data))
1327 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001328 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1329 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001330
Simon Glass75db0862016-11-25 20:15:55 -07001331 def testPackUbootSingleMicrocode(self):
1332 """Test that x86 microcode can be handled correctly with fdt_normal.
1333 """
Simon Glass160a7662017-05-27 07:38:26 -06001334 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001335
Simon Glassc49deb82016-11-25 20:15:54 -07001336 def testUBootImg(self):
1337 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001338 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001339 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001340
1341 def testNoMicrocode(self):
1342 """Test that a missing microcode region is detected"""
1343 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001344 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001345 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1346 "node found in ", str(e.exception))
1347
1348 def testMicrocodeWithoutNode(self):
1349 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1350 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001351 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001352 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1353 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1354
1355 def testMicrocodeWithoutNode2(self):
1356 """Test that a missing u-boot-ucode node is detected"""
1357 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001358 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001359 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1360 "microcode region u-boot-ucode", str(e.exception))
1361
1362 def testMicrocodeWithoutPtrInElf(self):
1363 """Test that a U-Boot binary without the microcode symbol is detected"""
1364 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001365 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001366 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001367 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001368
1369 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001370 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001371 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1372 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1373
1374 finally:
1375 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001376 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001377 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001378
1379 def testMicrocodeNotInImage(self):
1380 """Test that microcode must be placed within the image"""
1381 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001382 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001383 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1384 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001385 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001386
1387 def testWithoutMicrocode(self):
1388 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001389 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001390 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001391 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001392
1393 # Now check the device tree has no microcode
1394 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1395 second = data[len(U_BOOT_NODTB_DATA):]
1396
1397 fdt_len = self.GetFdtLen(second)
1398 self.assertEqual(dtb, second[:fdt_len])
1399
1400 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1401 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001402 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001403
1404 def testUnknownPosSize(self):
1405 """Test that microcode must be placed within the image"""
1406 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001407 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001408 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001409 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001410
1411 def testPackFsp(self):
1412 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001413 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001414 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1415
1416 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001417 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001418 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001419 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001420
1421 def testPackVbt(self):
1422 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001423 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001424 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001425
Simon Glass56509842017-11-12 21:52:25 -07001426 def testSplBssPad(self):
1427 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001428 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001429 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001430 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001431 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001432 data)
Simon Glass56509842017-11-12 21:52:25 -07001433
Simon Glass86af5112018-10-01 21:12:42 -06001434 def testSplBssPadMissing(self):
1435 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001436 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001437 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001438 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001439 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1440 str(e.exception))
1441
Simon Glass87722132017-11-12 21:52:26 -07001442 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001443 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001444 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001445 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1446
Simon Glass736bb0a2018-07-06 10:27:17 -06001447 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1448 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001449
1450 We expect to see the following in the image, in order:
1451 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1452 correct place
1453 u-boot.dtb with the microcode removed
1454 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001455
1456 Args:
1457 dts: Device tree file to use for test
1458 ucode_second: True if the microsecond entry is second instead of
1459 third
Simon Glass6b187df2017-11-12 21:52:27 -07001460 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001461 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001462 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1463 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001464 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1465 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001466
Simon Glass736bb0a2018-07-06 10:27:17 -06001467 def testPackUbootSplMicrocode(self):
1468 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001469 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001470 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001471
1472 def testPackUbootSplMicrocodeReorder(self):
1473 """Test that order doesn't matter for microcode entries
1474
1475 This is the same as testPackUbootSplMicrocode but when we process the
1476 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1477 entry, so we reply on binman to try later.
1478 """
Simon Glass741f2d62018-10-01 12:22:30 -06001479 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001480 ucode_second=True)
1481
Simon Glassca4f4ff2017-11-12 21:52:28 -07001482 def testPackMrc(self):
1483 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001484 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001485 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1486
Simon Glass47419ea2017-11-13 18:54:55 -07001487 def testSplDtb(self):
1488 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001489 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001490 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001491 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1492
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001493 def testSplNoDtb(self):
1494 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001495 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001496 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001497 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1498
Simon Glass3d433382021-03-21 18:24:30 +13001499 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4649bea2023-07-18 07:23:54 -06001500 use_expanded=False, no_write_symbols=False):
Simon Glassf5898822021-03-18 20:24:56 +13001501 """Check the image contains the expected symbol values
1502
1503 Args:
1504 dts: Device tree file to use for test
1505 base_data: Data before and after 'u-boot' section
1506 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001507 entry_args: Dict of entry args to supply to binman
1508 key: arg name
1509 value: value of that arg
1510 use_expanded: True to use expanded entries where available, e.g.
1511 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001512 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001513 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001514 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1515 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001516 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001517 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001518 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001519
Simon Glass11ae93e2018-10-01 21:12:47 -06001520 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001521 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1522 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001523 # The image should contain the symbols from u_boot_binman_syms.c
1524 # Note that image_pos is adjusted by the base address of the image,
1525 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001526 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1527 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001528 0x10 + u_boot_offset, 0x04)
Simon Glass4649bea2023-07-18 07:23:54 -06001529 if no_write_symbols:
1530 expected = (base_data +
1531 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1532 U_BOOT_DATA + base_data)
1533 else:
1534 expected = (sym_values + base_data[24:] +
1535 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1536 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001537 self.assertEqual(expected, data)
1538
Simon Glassf5898822021-03-18 20:24:56 +13001539 def testSymbols(self):
1540 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001541 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001542
1543 def testSymbolsNoDtb(self):
1544 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001545 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001546 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1547 0x38)
1548
Simon Glassdd57c132018-06-01 09:38:11 -06001549 def testPackUnitAddress(self):
1550 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001551 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001552 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1553
Simon Glass18546952018-06-01 09:38:16 -06001554 def testSections(self):
1555 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001556 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001557 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1558 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1559 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001560 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001561
Simon Glass3b0c3822018-06-01 09:38:20 -06001562 def testMap(self):
1563 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001564 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001565 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700156600000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600156700000000 00000000 00000010 section@0
156800000000 00000000 00000004 u-boot
156900000010 00000010 00000010 section@1
157000000010 00000000 00000004 u-boot
157100000020 00000020 00000004 section@2
157200000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001573''', map_data)
1574
Simon Glassc8d48ef2018-06-01 09:38:21 -06001575 def testNamePrefix(self):
1576 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001577 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001578 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700157900000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600158000000000 00000000 00000010 section@0
158100000000 00000000 00000004 ro-u-boot
158200000010 00000010 00000010 section@1
158300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001584''', map_data)
1585
Simon Glass736bb0a2018-07-06 10:27:17 -06001586 def testUnknownContents(self):
1587 """Test that obtaining the contents works as expected"""
1588 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001589 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001590 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001591 "processing of contents: remaining ["
1592 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001593
Simon Glass5c890232018-07-06 10:27:19 -06001594 def testBadChangeSize(self):
1595 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001596 try:
1597 state.SetAllowEntryExpansion(False)
1598 with self.assertRaises(ValueError) as e:
1599 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001600 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001601 str(e.exception))
1602 finally:
1603 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001604
Simon Glass16b8d6b2018-07-06 10:27:42 -06001605 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001606 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001607 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001608 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001609 dtb = fdt.Fdt(out_dtb_fname)
1610 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001611 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001612 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001613 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001614 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001615 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001616 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001617 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001618 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001619 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001620 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001621 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001622 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001623 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001624
Simon Glass3ab95982018-08-01 15:22:37 -06001625 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001626 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001627 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001628 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001629 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001630 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001631 'size': 40
1632 }, props)
1633
1634 def testUpdateFdtBad(self):
1635 """Test that we detect when ProcessFdt never completes"""
1636 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001637 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001638 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001639 '[<binman.etype._testing.Entry__testing',
1640 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001641
Simon Glass53af22a2018-07-17 13:25:32 -06001642 def testEntryArgs(self):
1643 """Test passing arguments to entries from the command line"""
1644 entry_args = {
1645 'test-str-arg': 'test1',
1646 'test-int-arg': '456',
1647 }
Simon Glass741f2d62018-10-01 12:22:30 -06001648 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001649 self.assertIn('image', control.images)
1650 entry = control.images['image'].GetEntries()['_testing']
1651 self.assertEqual('test0', entry.test_str_fdt)
1652 self.assertEqual('test1', entry.test_str_arg)
1653 self.assertEqual(123, entry.test_int_fdt)
1654 self.assertEqual(456, entry.test_int_arg)
1655
1656 def testEntryArgsMissing(self):
1657 """Test missing arguments and properties"""
1658 entry_args = {
1659 'test-int-arg': '456',
1660 }
Simon Glass741f2d62018-10-01 12:22:30 -06001661 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001662 entry = control.images['image'].GetEntries()['_testing']
1663 self.assertEqual('test0', entry.test_str_fdt)
1664 self.assertEqual(None, entry.test_str_arg)
1665 self.assertEqual(None, entry.test_int_fdt)
1666 self.assertEqual(456, entry.test_int_arg)
1667
1668 def testEntryArgsRequired(self):
1669 """Test missing arguments and properties"""
1670 entry_args = {
1671 'test-int-arg': '456',
1672 }
1673 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001674 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001675 self.assertIn("Node '/binman/_testing': "
1676 'Missing required properties/entry args: test-str-arg, '
1677 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001678 str(e.exception))
1679
1680 def testEntryArgsInvalidFormat(self):
1681 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001682 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1683 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001684 with self.assertRaises(ValueError) as e:
1685 self._DoBinman(*args)
1686 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1687
1688 def testEntryArgsInvalidInteger(self):
1689 """Test that an invalid entry-argument integer is detected"""
1690 entry_args = {
1691 'test-int-arg': 'abc',
1692 }
1693 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001694 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001695 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1696 "'test-int-arg' (value 'abc') to integer",
1697 str(e.exception))
1698
1699 def testEntryArgsInvalidDatatype(self):
1700 """Test that an invalid entry-argument datatype is detected
1701
1702 This test could be written in entry_test.py except that it needs
1703 access to control.entry_args, which seems more than that module should
1704 be able to see.
1705 """
1706 entry_args = {
1707 'test-bad-datatype-arg': '12',
1708 }
1709 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001710 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001711 entry_args=entry_args)
1712 self.assertIn('GetArg() internal error: Unknown data type ',
1713 str(e.exception))
1714
Simon Glassbb748372018-07-17 13:25:33 -06001715 def testText(self):
1716 """Test for a text entry type"""
1717 entry_args = {
1718 'test-id': TEXT_DATA,
1719 'test-id2': TEXT_DATA2,
1720 'test-id3': TEXT_DATA3,
1721 }
Simon Glass741f2d62018-10-01 12:22:30 -06001722 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001723 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001724 expected = (tools.to_bytes(TEXT_DATA) +
1725 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1726 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001727 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001728 self.assertEqual(expected, data)
1729
Simon Glassfd8d1f72018-07-17 13:25:36 -06001730 def testEntryDocs(self):
1731 """Test for creation of entry documentation"""
1732 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001733 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001734 self.assertTrue(len(stdout.getvalue()) > 0)
1735
1736 def testEntryDocsMissing(self):
1737 """Test handling of missing entry documentation"""
1738 with self.assertRaises(ValueError) as e:
1739 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001740 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001741 self.assertIn('Documentation is missing for modules: u_boot',
1742 str(e.exception))
1743
Simon Glass11e36cc2018-07-17 13:25:38 -06001744 def testFmap(self):
1745 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001746 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001747 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001748 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1749 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001750 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001751 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001752 self.assertEqual(1, fhdr.ver_major)
1753 self.assertEqual(0, fhdr.ver_minor)
1754 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001755 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001756 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001757 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001758 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001759 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001760
Simon Glassc7722e82021-04-03 11:05:09 +13001761 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001762 self.assertEqual(b'SECTION0', fentry.name)
1763 self.assertEqual(0, fentry.offset)
1764 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001765 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001766
1767 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001768 self.assertEqual(b'RO_U_BOOT', fentry.name)
1769 self.assertEqual(0, fentry.offset)
1770 self.assertEqual(4, fentry.size)
1771 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001772
Simon Glassc7722e82021-04-03 11:05:09 +13001773 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001774 self.assertEqual(b'SECTION1', fentry.name)
1775 self.assertEqual(16, fentry.offset)
1776 self.assertEqual(16, fentry.size)
1777 self.assertEqual(0, fentry.flags)
1778
1779 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001780 self.assertEqual(b'RW_U_BOOT', fentry.name)
1781 self.assertEqual(16, fentry.offset)
1782 self.assertEqual(4, fentry.size)
1783 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001784
Simon Glassc7722e82021-04-03 11:05:09 +13001785 fentry = next(fiter)
1786 self.assertEqual(b'FMAP', fentry.name)
1787 self.assertEqual(32, fentry.offset)
1788 self.assertEqual(expect_size, fentry.size)
1789 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001790
Simon Glassec127af2018-07-17 13:25:39 -06001791 def testBlobNamedByArg(self):
1792 """Test we can add a blob with the filename coming from an entry arg"""
1793 entry_args = {
1794 'cros-ec-rw-path': 'ecrw.bin',
1795 }
Simon Glass3decfa32020-09-01 05:13:54 -06001796 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001797
Simon Glass3af8e492018-07-17 13:25:40 -06001798 def testFill(self):
1799 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001800 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001801 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001802 self.assertEqual(expected, data)
1803
1804 def testFillNoSize(self):
1805 """Test for an fill entry type with no size"""
1806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001807 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001808 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001809 str(e.exception))
1810
Simon Glass0ef87aa2018-07-17 13:25:44 -06001811 def _HandleGbbCommand(self, pipe_list):
1812 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001813 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001814 fname = pipe_list[0][-1]
1815 # Append our GBB data to the file, which will happen every time the
1816 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001817 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001818 fd.write(GBB_DATA)
1819 return command.CommandResult()
1820
1821 def testGbb(self):
1822 """Test for the Chromium OS Google Binary Block"""
1823 command.test_result = self._HandleGbbCommand
1824 entry_args = {
1825 'keydir': 'devkeys',
1826 'bmpblk': 'bmpblk.bin',
1827 }
Simon Glass741f2d62018-10-01 12:22:30 -06001828 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001829
1830 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001831 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1832 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001833 self.assertEqual(expected, data)
1834
1835 def testGbbTooSmall(self):
1836 """Test for the Chromium OS Google Binary Block being large enough"""
1837 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001838 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001839 self.assertIn("Node '/binman/gbb': GBB is too small",
1840 str(e.exception))
1841
1842 def testGbbNoSize(self):
1843 """Test for the Chromium OS Google Binary Block having a size"""
1844 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001845 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001846 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1847 str(e.exception))
1848
Simon Glass4f9ee832022-01-09 20:14:09 -07001849 def testGbbMissing(self):
1850 """Test that binman still produces an image if futility is missing"""
1851 entry_args = {
1852 'keydir': 'devkeys',
1853 }
1854 with test_util.capture_sys_output() as (_, stderr):
1855 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1856 entry_args=entry_args)
1857 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001858 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001859
Simon Glass24d0d3c2018-07-17 13:25:47 -06001860 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001861 """Fake calls to the futility utility
1862
1863 The expected pipe is:
1864
1865 [('futility', 'vbutil_firmware', '--vblock',
1866 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1867 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1868 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1869 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1870
1871 This writes to the output file (here, 'vblock.vblock'). If
1872 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1873 of the input data (here, 'input.vblock').
1874 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001875 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001876 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001877 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001878 if self._hash_data:
1879 infile = pipe_list[0][11]
1880 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001881 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001882 m.update(data)
1883 fd.write(m.digest())
1884 else:
1885 fd.write(VBLOCK_DATA)
1886
Simon Glass24d0d3c2018-07-17 13:25:47 -06001887 return command.CommandResult()
1888
1889 def testVblock(self):
1890 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001891 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001892 command.test_result = self._HandleVblockCommand
1893 entry_args = {
1894 'keydir': 'devkeys',
1895 }
Simon Glass741f2d62018-10-01 12:22:30 -06001896 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001897 entry_args=entry_args)
1898 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1899 self.assertEqual(expected, data)
1900
1901 def testVblockNoContent(self):
1902 """Test we detect a vblock which has no content to sign"""
1903 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001904 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001905 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001906 'property', str(e.exception))
1907
1908 def testVblockBadPhandle(self):
1909 """Test that we detect a vblock with an invalid phandle in contents"""
1910 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001911 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001912 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1913 '1000', str(e.exception))
1914
1915 def testVblockBadEntry(self):
1916 """Test that we detect an entry that points to a non-entry"""
1917 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001918 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001919 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1920 "'other'", str(e.exception))
1921
Simon Glass5af9ebc2021-01-06 21:35:17 -07001922 def testVblockContent(self):
1923 """Test that the vblock signs the right data"""
1924 self._hash_data = True
1925 command.test_result = self._HandleVblockCommand
1926 entry_args = {
1927 'keydir': 'devkeys',
1928 }
1929 data = self._DoReadFileDtb(
1930 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1931 entry_args=entry_args)[0]
1932 hashlen = 32 # SHA256 hash is 32 bytes
1933 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1934 hashval = data[-hashlen:]
1935 dtb = data[len(U_BOOT_DATA):-hashlen]
1936
1937 expected_data = U_BOOT_DATA + dtb
1938
1939 # The hashval should be a hash of the dtb
1940 m = hashlib.sha256()
1941 m.update(expected_data)
1942 expected_hashval = m.digest()
1943 self.assertEqual(expected_hashval, hashval)
1944
Simon Glass4f9ee832022-01-09 20:14:09 -07001945 def testVblockMissing(self):
1946 """Test that binman still produces an image if futility is missing"""
1947 entry_args = {
1948 'keydir': 'devkeys',
1949 }
1950 with test_util.capture_sys_output() as (_, stderr):
1951 self._DoTestFile('074_vblock.dts',
1952 force_missing_bintools='futility',
1953 entry_args=entry_args)
1954 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001955 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001956
Simon Glassb8ef5b62018-07-17 13:25:48 -06001957 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001958 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001959 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001960 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001961 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001962 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1963
Simon Glass15a587c2018-07-17 13:25:51 -06001964 def testUsesPos(self):
1965 """Test that the 'pos' property cannot be used anymore"""
1966 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001967 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001968 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1969 "'pos'", str(e.exception))
1970
Simon Glassd178eab2018-09-14 04:57:08 -06001971 def testFillZero(self):
1972 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001973 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001974 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001975
Simon Glass0b489362018-09-14 04:57:09 -06001976 def testTextMissing(self):
1977 """Test for a text entry type where there is no text"""
1978 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001979 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001980 self.assertIn("Node '/binman/text': No value provided for text label "
1981 "'test-id'", str(e.exception))
1982
Simon Glass35b384c2018-09-14 04:57:10 -06001983 def testPackStart16Tpl(self):
1984 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001985 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001986 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1987
Simon Glass0bfa7b02018-09-14 04:57:12 -06001988 def testSelectImage(self):
1989 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001990 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001991
Simon Glasseb833d82019-04-25 21:58:34 -06001992 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001993 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001994 with test_util.capture_sys_output() as (stdout, stderr):
1995 retcode = self._DoTestFile('006_dual_image.dts',
1996 verbosity=verbosity,
1997 images=['image2'])
1998 self.assertEqual(0, retcode)
1999 if verbosity:
2000 self.assertIn(expected, stdout.getvalue())
2001 else:
2002 self.assertNotIn(expected, stdout.getvalue())
2003
Simon Glassc1aa66e2022-01-29 14:14:04 -07002004 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2005 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06002006 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06002007
Simon Glass6ed45ba2018-09-14 04:57:24 -06002008 def testUpdateFdtAll(self):
2009 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06002010 self._SetupSplElf()
2011 self._SetupTplElf()
Simon Glass3c081312019-07-08 14:25:26 -06002012 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06002013
2014 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06002015 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002016 'image-pos': 0,
2017 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002018 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002019 'section:image-pos': 0,
2020 'section:size': 565,
2021 'section/u-boot-dtb:offset': 0,
2022 'section/u-boot-dtb:image-pos': 0,
2023 'section/u-boot-dtb:size': 565,
2024 'u-boot-spl-dtb:offset': 565,
2025 'u-boot-spl-dtb:image-pos': 565,
2026 'u-boot-spl-dtb:size': 585,
2027 'u-boot-tpl-dtb:offset': 1150,
2028 'u-boot-tpl-dtb:image-pos': 1150,
2029 'u-boot-tpl-dtb:size': 585,
2030 'u-boot-vpl-dtb:image-pos': 1735,
2031 'u-boot-vpl-dtb:offset': 1735,
2032 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002033 }
2034
2035 # We expect three device-tree files in the output, one after the other.
2036 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2037 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2038 # main U-Boot tree. All three should have the same postions and offset.
2039 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07002040 self.maxDiff = None
2041 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002042 dtb = fdt.Fdt.FromData(data[start:])
2043 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06002044 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07002045 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06002046 expected = dict(base_expected)
2047 if item:
2048 expected[item] = 0
2049 self.assertEqual(expected, props)
2050 start += dtb._fdt_obj.totalsize()
2051
2052 def testUpdateFdtOutput(self):
2053 """Test that output DTB files are updated"""
2054 try:
Simon Glass741f2d62018-10-01 12:22:30 -06002055 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06002056 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2057
2058 # Unfortunately, compiling a source file always results in a file
2059 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002060 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002061 # binman as a file called u-boot.dtb. To fix this, copy the file
2062 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002063 start = 0
2064 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002065 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002066 dtb = fdt.Fdt.FromData(data[start:])
2067 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002068 pathname = tools.get_output_filename(os.path.split(fname)[1])
2069 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002070 name = os.path.split(fname)[0]
2071
2072 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002073 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002074 else:
2075 orig_indata = dtb_data
2076 self.assertNotEqual(outdata, orig_indata,
2077 "Expected output file '%s' be updated" % pathname)
2078 self.assertEqual(outdata, data[start:start + size],
2079 "Expected output file '%s' to match output image" %
2080 pathname)
2081 start += size
2082 finally:
2083 self._ResetDtbs()
2084
Simon Glass83d73c22018-09-14 04:57:26 -06002085 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002086 bintool = self.comp_bintools['lz4']
2087 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002088
2089 def testCompress(self):
2090 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002091 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002092 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002093 use_real_dtb=True, update_dtb=True)
2094 dtb = fdt.Fdt(out_dtb_fname)
2095 dtb.Scan()
2096 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2097 orig = self._decompress(data)
2098 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002099
2100 # Do a sanity check on various fields
2101 image = control.images['image']
2102 entries = image.GetEntries()
2103 self.assertEqual(1, len(entries))
2104
2105 entry = entries['blob']
2106 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2107 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2108 orig = self._decompress(entry.data)
2109 self.assertEqual(orig, entry.uncomp_data)
2110
Simon Glass63e7ba62020-10-26 17:40:16 -06002111 self.assertEqual(image.data, entry.data)
2112
Simon Glass83d73c22018-09-14 04:57:26 -06002113 expected = {
2114 'blob:uncomp-size': len(COMPRESS_DATA),
2115 'blob:size': len(data),
2116 'size': len(data),
2117 }
2118 self.assertEqual(expected, props)
2119
Simon Glass0a98b282018-09-14 04:57:28 -06002120 def testFiles(self):
2121 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002122 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002123 self.assertEqual(FILES_DATA, data)
2124
2125 def testFilesCompress(self):
2126 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002127 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002128 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002129
2130 image = control.images['image']
2131 entries = image.GetEntries()
2132 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002133 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002134
Simon Glassc6c10e72019-05-17 22:00:46 -06002135 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002136 for i in range(1, 3):
2137 key = '%d.dat' % i
2138 start = entries[key].image_pos
2139 len = entries[key].size
2140 chunk = data[start:start + len]
2141 orig += self._decompress(chunk)
2142
2143 self.assertEqual(FILES_DATA, orig)
2144
2145 def testFilesMissing(self):
2146 """Test missing files"""
2147 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002148 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002149 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2150 'no files', str(e.exception))
2151
2152 def testFilesNoPattern(self):
2153 """Test missing files"""
2154 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002155 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002156 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2157 str(e.exception))
2158
Simon Glass80a66ae2022-03-05 20:18:59 -07002159 def testExtendSize(self):
2160 """Test an extending entry"""
2161 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002162 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002163 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2164 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2165 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2166 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002167 self.assertEqual(expect, data)
2168 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700216900000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600217000000000 00000000 00000008 fill
217100000008 00000008 00000004 u-boot
21720000000c 0000000c 00000004 section
21730000000c 00000000 00000003 intel-mrc
217400000010 00000010 00000004 u-boot2
217500000014 00000014 0000000c section2
217600000014 00000000 00000008 fill
21770000001c 00000008 00000004 u-boot
217800000020 00000020 00000008 fill2
2179''', map_data)
2180
Simon Glass80a66ae2022-03-05 20:18:59 -07002181 def testExtendSizeBad(self):
2182 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002183 with test_util.capture_sys_output() as (stdout, stderr):
2184 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002185 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002186 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2187 'expanding entry', str(e.exception))
2188
Simon Glasse0e5df92018-09-14 04:57:31 -06002189 def testHash(self):
2190 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002191 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002192 use_real_dtb=True, update_dtb=True)
2193 dtb = fdt.Fdt(out_dtb_fname)
2194 dtb.Scan()
2195 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2196 m = hashlib.sha256()
2197 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002198 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002199
2200 def testHashNoAlgo(self):
2201 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002202 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002203 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2204 'hash node', str(e.exception))
2205
2206 def testHashBadAlgo(self):
2207 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002208 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002209 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002210 str(e.exception))
2211
2212 def testHashSection(self):
2213 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002214 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002215 use_real_dtb=True, update_dtb=True)
2216 dtb = fdt.Fdt(out_dtb_fname)
2217 dtb.Scan()
2218 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2219 m = hashlib.sha256()
2220 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002221 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002222 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002223
Simon Glassf0253632018-09-14 04:57:32 -06002224 def testPackUBootTplMicrocode(self):
2225 """Test that x86 microcode can be handled correctly in TPL
2226
2227 We expect to see the following in the image, in order:
2228 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2229 place
2230 u-boot-tpl.dtb with the microcode removed
2231 the microcode
2232 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002233 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002234 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002235 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002236 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2237 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002238
Simon Glassf8f8df62018-09-14 04:57:34 -06002239 def testFmapX86(self):
2240 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002241 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002242 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002243 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002244 self.assertEqual(expected, data[:32])
2245 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2246
2247 self.assertEqual(0x100, fhdr.image_size)
2248
2249 self.assertEqual(0, fentries[0].offset)
2250 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002251 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002252
2253 self.assertEqual(4, fentries[1].offset)
2254 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002255 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002256
2257 self.assertEqual(32, fentries[2].offset)
2258 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2259 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002260 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002261
2262 def testFmapX86Section(self):
2263 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002264 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002265 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002266 self.assertEqual(expected, data[:32])
2267 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2268
Simon Glass17365752021-04-03 11:05:10 +13002269 self.assertEqual(0x180, fhdr.image_size)
2270 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002271 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002272
Simon Glassc7722e82021-04-03 11:05:09 +13002273 fentry = next(fiter)
2274 self.assertEqual(b'U_BOOT', fentry.name)
2275 self.assertEqual(0, fentry.offset)
2276 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002277
Simon Glassc7722e82021-04-03 11:05:09 +13002278 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002279 self.assertEqual(b'SECTION', fentry.name)
2280 self.assertEqual(4, fentry.offset)
2281 self.assertEqual(0x20 + expect_size, fentry.size)
2282
2283 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002284 self.assertEqual(b'INTEL_MRC', fentry.name)
2285 self.assertEqual(4, fentry.offset)
2286 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002287
Simon Glassc7722e82021-04-03 11:05:09 +13002288 fentry = next(fiter)
2289 self.assertEqual(b'FMAP', fentry.name)
2290 self.assertEqual(36, fentry.offset)
2291 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002292
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002293 def testElf(self):
2294 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002295 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002296 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002297 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002298 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002299 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002300
Simon Glass093d1682019-07-08 13:18:25 -06002301 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002302 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002303 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002304 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002305 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002306 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002307
Simon Glass163ed6c2018-09-14 04:57:36 -06002308 def testPackOverlapMap(self):
2309 """Test that overlapping regions are detected"""
2310 with test_util.capture_sys_output() as (stdout, stderr):
2311 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002312 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002313 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002314 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2315 stdout.getvalue())
2316
2317 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002318 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002319 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002320 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002321 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002322<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002323<none> 00000000 00000004 u-boot
2324<none> 00000003 00000004 u-boot-align
2325''', map_data)
2326
Simon Glass093d1682019-07-08 13:18:25 -06002327 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002328 """Test that an image with an Intel Reference code binary works"""
2329 data = self._DoReadFile('100_intel_refcode.dts')
2330 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2331
Simon Glass9481c802019-04-25 21:58:39 -06002332 def testSectionOffset(self):
2333 """Tests use of a section with an offset"""
2334 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2335 map=True)
2336 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700233700000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600233800000004 00000004 00000010 section@0
233900000004 00000000 00000004 u-boot
234000000018 00000018 00000010 section@1
234100000018 00000000 00000004 u-boot
23420000002c 0000002c 00000004 section@2
23430000002c 00000000 00000004 u-boot
2344''', map_data)
2345 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002346 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2347 tools.get_bytes(0x21, 12) +
2348 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2349 tools.get_bytes(0x61, 12) +
2350 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2351 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002352
Simon Glassac62fba2019-07-08 13:18:53 -06002353 def testCbfsRaw(self):
2354 """Test base handling of a Coreboot Filesystem (CBFS)
2355
2356 The exact contents of the CBFS is verified by similar tests in
2357 cbfs_util_test.py. The tests here merely check that the files added to
2358 the CBFS can be found in the final image.
2359 """
2360 data = self._DoReadFile('102_cbfs_raw.dts')
2361 size = 0xb0
2362
2363 cbfs = cbfs_util.CbfsReader(data)
2364 self.assertEqual(size, cbfs.rom_size)
2365
2366 self.assertIn('u-boot-dtb', cbfs.files)
2367 cfile = cbfs.files['u-boot-dtb']
2368 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2369
2370 def testCbfsArch(self):
2371 """Test on non-x86 architecture"""
2372 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2373 size = 0x100
2374
2375 cbfs = cbfs_util.CbfsReader(data)
2376 self.assertEqual(size, cbfs.rom_size)
2377
2378 self.assertIn('u-boot-dtb', cbfs.files)
2379 cfile = cbfs.files['u-boot-dtb']
2380 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2381
2382 def testCbfsStage(self):
2383 """Tests handling of a Coreboot Filesystem (CBFS)"""
2384 if not elf.ELF_TOOLS:
2385 self.skipTest('Python elftools not available')
2386 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2387 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2388 size = 0xb0
2389
2390 data = self._DoReadFile('104_cbfs_stage.dts')
2391 cbfs = cbfs_util.CbfsReader(data)
2392 self.assertEqual(size, cbfs.rom_size)
2393
2394 self.assertIn('u-boot', cbfs.files)
2395 cfile = cbfs.files['u-boot']
2396 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2397
2398 def testCbfsRawCompress(self):
2399 """Test handling of compressing raw files"""
2400 self._CheckLz4()
2401 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2402 size = 0x140
2403
2404 cbfs = cbfs_util.CbfsReader(data)
2405 self.assertIn('u-boot', cbfs.files)
2406 cfile = cbfs.files['u-boot']
2407 self.assertEqual(COMPRESS_DATA, cfile.data)
2408
2409 def testCbfsBadArch(self):
2410 """Test handling of a bad architecture"""
2411 with self.assertRaises(ValueError) as e:
2412 self._DoReadFile('106_cbfs_bad_arch.dts')
2413 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2414
2415 def testCbfsNoSize(self):
2416 """Test handling of a missing size property"""
2417 with self.assertRaises(ValueError) as e:
2418 self._DoReadFile('107_cbfs_no_size.dts')
2419 self.assertIn('entry must have a size property', str(e.exception))
2420
Simon Glasse2f04742021-11-23 11:03:54 -07002421 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002422 """Test handling of a CBFS entry which does not provide contentsy"""
2423 with self.assertRaises(ValueError) as e:
2424 self._DoReadFile('108_cbfs_no_contents.dts')
2425 self.assertIn('Could not complete processing of contents',
2426 str(e.exception))
2427
2428 def testCbfsBadCompress(self):
2429 """Test handling of a bad architecture"""
2430 with self.assertRaises(ValueError) as e:
2431 self._DoReadFile('109_cbfs_bad_compress.dts')
2432 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2433 str(e.exception))
2434
2435 def testCbfsNamedEntries(self):
2436 """Test handling of named entries"""
2437 data = self._DoReadFile('110_cbfs_name.dts')
2438
2439 cbfs = cbfs_util.CbfsReader(data)
2440 self.assertIn('FRED', cbfs.files)
2441 cfile1 = cbfs.files['FRED']
2442 self.assertEqual(U_BOOT_DATA, cfile1.data)
2443
2444 self.assertIn('hello', cbfs.files)
2445 cfile2 = cbfs.files['hello']
2446 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2447
Simon Glassc5ac1382019-07-08 13:18:54 -06002448 def _SetupIfwi(self, fname):
2449 """Set up to run an IFWI test
2450
2451 Args:
2452 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2453 """
2454 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002455 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002456
2457 # Intel Integrated Firmware Image (IFWI) file
2458 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2459 data = fd.read()
2460 TestFunctional._MakeInputFile(fname,data)
2461
2462 def _CheckIfwi(self, data):
2463 """Check that an image with an IFWI contains the correct output
2464
2465 Args:
2466 data: Conents of output file
2467 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002468 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002469 if data[:0x1000] != expected_desc:
2470 self.fail('Expected descriptor binary at start of image')
2471
2472 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002473 image_fname = tools.get_output_filename('image.bin')
2474 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002475 ifwitool = bintool.Bintool.create('ifwitool')
2476 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002477
Simon Glassc1aa66e2022-01-29 14:14:04 -07002478 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002479 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002480
2481 def testPackX86RomIfwi(self):
2482 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2483 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002484 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002485 self._CheckIfwi(data)
2486
2487 def testPackX86RomIfwiNoDesc(self):
2488 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2489 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002490 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002491 self._CheckIfwi(data)
2492
2493 def testPackX86RomIfwiNoData(self):
2494 """Test that an x86 ROM with IFWI handles missing data"""
2495 self._SetupIfwi('ifwi.bin')
2496 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002497 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002498 self.assertIn('Could not complete processing of contents',
2499 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002500
Simon Glass4f9ee832022-01-09 20:14:09 -07002501 def testIfwiMissing(self):
2502 """Test that binman still produces an image if ifwitool is missing"""
2503 self._SetupIfwi('fitimage.bin')
2504 with test_util.capture_sys_output() as (_, stderr):
2505 self._DoTestFile('111_x86_rom_ifwi.dts',
2506 force_missing_bintools='ifwitool')
2507 err = stderr.getvalue()
2508 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002509 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002510
Simon Glasse073d4e2019-07-08 13:18:56 -06002511 def testCbfsOffset(self):
2512 """Test a CBFS with files at particular offsets
2513
2514 Like all CFBS tests, this is just checking the logic that calls
2515 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2516 """
2517 data = self._DoReadFile('114_cbfs_offset.dts')
2518 size = 0x200
2519
2520 cbfs = cbfs_util.CbfsReader(data)
2521 self.assertEqual(size, cbfs.rom_size)
2522
2523 self.assertIn('u-boot', cbfs.files)
2524 cfile = cbfs.files['u-boot']
2525 self.assertEqual(U_BOOT_DATA, cfile.data)
2526 self.assertEqual(0x40, cfile.cbfs_offset)
2527
2528 self.assertIn('u-boot-dtb', cbfs.files)
2529 cfile2 = cbfs.files['u-boot-dtb']
2530 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2531 self.assertEqual(0x140, cfile2.cbfs_offset)
2532
Simon Glass086cec92019-07-08 14:25:27 -06002533 def testFdtmap(self):
2534 """Test an FDT map can be inserted in the image"""
2535 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2536 fdtmap_data = data[len(U_BOOT_DATA):]
2537 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002538 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002539 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002540
2541 fdt_data = fdtmap_data[16:]
2542 dtb = fdt.Fdt.FromData(fdt_data)
2543 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002544 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002545 self.assertEqual({
2546 'image-pos': 0,
2547 'offset': 0,
2548 'u-boot:offset': 0,
2549 'u-boot:size': len(U_BOOT_DATA),
2550 'u-boot:image-pos': 0,
2551 'fdtmap:image-pos': 4,
2552 'fdtmap:offset': 4,
2553 'fdtmap:size': len(fdtmap_data),
2554 'size': len(data),
2555 }, props)
2556
2557 def testFdtmapNoMatch(self):
2558 """Check handling of an FDT map when the section cannot be found"""
2559 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2560
2561 # Mangle the section name, which should cause a mismatch between the
2562 # correct FDT path and the one expected by the section
2563 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002564 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002565 entries = image.GetEntries()
2566 fdtmap = entries['fdtmap']
2567 with self.assertRaises(ValueError) as e:
2568 fdtmap._GetFdtmap()
2569 self.assertIn("Cannot locate node for path '/binman-suffix'",
2570 str(e.exception))
2571
Simon Glasscf228942019-07-08 14:25:28 -06002572 def testFdtmapHeader(self):
2573 """Test an FDT map and image header can be inserted in the image"""
2574 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2575 fdtmap_pos = len(U_BOOT_DATA)
2576 fdtmap_data = data[fdtmap_pos:]
2577 fdt_data = fdtmap_data[16:]
2578 dtb = fdt.Fdt.FromData(fdt_data)
2579 fdt_size = dtb.GetFdtObj().totalsize()
2580 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002581 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002582 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2583 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2584
2585 def testFdtmapHeaderStart(self):
2586 """Test an image header can be inserted at the image start"""
2587 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2588 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2589 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002590 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002591 offset = struct.unpack('<I', hdr_data[4:])[0]
2592 self.assertEqual(fdtmap_pos, offset)
2593
2594 def testFdtmapHeaderPos(self):
2595 """Test an image header can be inserted at a chosen position"""
2596 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2597 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2598 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002599 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002600 offset = struct.unpack('<I', hdr_data[4:])[0]
2601 self.assertEqual(fdtmap_pos, offset)
2602
2603 def testHeaderMissingFdtmap(self):
2604 """Test an image header requires an fdtmap"""
2605 with self.assertRaises(ValueError) as e:
2606 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2607 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2608 str(e.exception))
2609
2610 def testHeaderNoLocation(self):
2611 """Test an image header with a no specified location is detected"""
2612 with self.assertRaises(ValueError) as e:
2613 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2614 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2615 str(e.exception))
2616
Simon Glassc52c9e72019-07-08 14:25:37 -06002617 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002618 """Test extending an entry after it is packed"""
2619 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002620 self.assertEqual(b'aaa', data[:3])
2621 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2622 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002623
Simon Glass80a66ae2022-03-05 20:18:59 -07002624 def testEntryExtendBad(self):
2625 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002626 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002627 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002628 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002629 str(e.exception))
2630
Simon Glass80a66ae2022-03-05 20:18:59 -07002631 def testEntryExtendSection(self):
2632 """Test extending an entry within a section after it is packed"""
2633 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002634 self.assertEqual(b'aaa', data[:3])
2635 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2636 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002637
Simon Glass6c223fd2019-07-08 14:25:38 -06002638 def testCompressDtb(self):
2639 """Test that compress of device-tree files is supported"""
2640 self._CheckLz4()
2641 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2642 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2643 comp_data = data[len(U_BOOT_DATA):]
2644 orig = self._decompress(comp_data)
2645 dtb = fdt.Fdt.FromData(orig)
2646 dtb.Scan()
2647 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2648 expected = {
2649 'u-boot:size': len(U_BOOT_DATA),
2650 'u-boot-dtb:uncomp-size': len(orig),
2651 'u-boot-dtb:size': len(comp_data),
2652 'size': len(data),
2653 }
2654 self.assertEqual(expected, props)
2655
Simon Glass69f7cb32019-07-08 14:25:41 -06002656 def testCbfsUpdateFdt(self):
2657 """Test that we can update the device tree with CBFS offset/size info"""
2658 self._CheckLz4()
2659 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2660 update_dtb=True)
2661 dtb = fdt.Fdt(out_dtb_fname)
2662 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002663 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002664 del props['cbfs/u-boot:size']
2665 self.assertEqual({
2666 'offset': 0,
2667 'size': len(data),
2668 'image-pos': 0,
2669 'cbfs:offset': 0,
2670 'cbfs:size': len(data),
2671 'cbfs:image-pos': 0,
Simon Glassab326012023-10-14 14:40:28 -06002672 'cbfs/u-boot:offset': 0x30,
Simon Glass69f7cb32019-07-08 14:25:41 -06002673 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassab326012023-10-14 14:40:28 -06002674 'cbfs/u-boot:image-pos': 0x30,
2675 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass69f7cb32019-07-08 14:25:41 -06002676 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassab326012023-10-14 14:40:28 -06002677 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass69f7cb32019-07-08 14:25:41 -06002678 }, props)
2679
Simon Glass8a1ad062019-07-08 14:25:42 -06002680 def testCbfsBadType(self):
2681 """Test an image header with a no specified location is detected"""
2682 with self.assertRaises(ValueError) as e:
2683 self._DoReadFile('126_cbfs_bad_type.dts')
2684 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2685
Simon Glass41b8ba02019-07-08 14:25:43 -06002686 def testList(self):
2687 """Test listing the files in an image"""
2688 self._CheckLz4()
2689 data = self._DoReadFile('127_list.dts')
2690 image = control.images['image']
2691 entries = image.BuildEntryList()
2692 self.assertEqual(7, len(entries))
2693
2694 ent = entries[0]
2695 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002696 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002697 self.assertEqual('section', ent.etype)
2698 self.assertEqual(len(data), ent.size)
2699 self.assertEqual(0, ent.image_pos)
2700 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002701 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002702
2703 ent = entries[1]
2704 self.assertEqual(1, ent.indent)
2705 self.assertEqual('u-boot', ent.name)
2706 self.assertEqual('u-boot', ent.etype)
2707 self.assertEqual(len(U_BOOT_DATA), ent.size)
2708 self.assertEqual(0, ent.image_pos)
2709 self.assertEqual(None, ent.uncomp_size)
2710 self.assertEqual(0, ent.offset)
2711
2712 ent = entries[2]
2713 self.assertEqual(1, ent.indent)
2714 self.assertEqual('section', ent.name)
2715 self.assertEqual('section', ent.etype)
2716 section_size = ent.size
2717 self.assertEqual(0x100, ent.image_pos)
2718 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002719 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002720
2721 ent = entries[3]
2722 self.assertEqual(2, ent.indent)
2723 self.assertEqual('cbfs', ent.name)
2724 self.assertEqual('cbfs', ent.etype)
2725 self.assertEqual(0x400, ent.size)
2726 self.assertEqual(0x100, ent.image_pos)
2727 self.assertEqual(None, ent.uncomp_size)
2728 self.assertEqual(0, ent.offset)
2729
2730 ent = entries[4]
2731 self.assertEqual(3, ent.indent)
2732 self.assertEqual('u-boot', ent.name)
2733 self.assertEqual('u-boot', ent.etype)
2734 self.assertEqual(len(U_BOOT_DATA), ent.size)
2735 self.assertEqual(0x138, ent.image_pos)
2736 self.assertEqual(None, ent.uncomp_size)
2737 self.assertEqual(0x38, ent.offset)
2738
2739 ent = entries[5]
2740 self.assertEqual(3, ent.indent)
2741 self.assertEqual('u-boot-dtb', ent.name)
2742 self.assertEqual('text', ent.etype)
2743 self.assertGreater(len(COMPRESS_DATA), ent.size)
2744 self.assertEqual(0x178, ent.image_pos)
2745 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2746 self.assertEqual(0x78, ent.offset)
2747
2748 ent = entries[6]
2749 self.assertEqual(2, ent.indent)
2750 self.assertEqual('u-boot-dtb', ent.name)
2751 self.assertEqual('u-boot-dtb', ent.etype)
2752 self.assertEqual(0x500, ent.image_pos)
2753 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2754 dtb_size = ent.size
2755 # Compressing this data expands it since headers are added
2756 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2757 self.assertEqual(0x400, ent.offset)
2758
2759 self.assertEqual(len(data), 0x100 + section_size)
2760 self.assertEqual(section_size, 0x400 + dtb_size)
2761
Simon Glasse1925fa2019-07-08 14:25:44 -06002762 def testFindFdtmap(self):
2763 """Test locating an FDT map in an image"""
2764 self._CheckLz4()
2765 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2766 image = control.images['image']
2767 entries = image.GetEntries()
2768 entry = entries['fdtmap']
2769 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2770
2771 def testFindFdtmapMissing(self):
2772 """Test failing to locate an FDP map"""
2773 data = self._DoReadFile('005_simple.dts')
2774 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2775
Simon Glass2d260032019-07-08 14:25:45 -06002776 def testFindImageHeader(self):
2777 """Test locating a image header"""
2778 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002779 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002780 image = control.images['image']
2781 entries = image.GetEntries()
2782 entry = entries['fdtmap']
2783 # The header should point to the FDT map
2784 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2785
2786 def testFindImageHeaderStart(self):
2787 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002788 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002789 image = control.images['image']
2790 entries = image.GetEntries()
2791 entry = entries['fdtmap']
2792 # The header should point to the FDT map
2793 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2794
2795 def testFindImageHeaderMissing(self):
2796 """Test failing to locate an image header"""
2797 data = self._DoReadFile('005_simple.dts')
2798 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2799
Simon Glassffded752019-07-08 14:25:46 -06002800 def testReadImage(self):
2801 """Test reading an image and accessing its FDT map"""
2802 self._CheckLz4()
2803 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002804 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002805 orig_image = control.images['image']
2806 image = Image.FromFile(image_fname)
2807 self.assertEqual(orig_image.GetEntries().keys(),
2808 image.GetEntries().keys())
2809
2810 orig_entry = orig_image.GetEntries()['fdtmap']
2811 entry = image.GetEntries()['fdtmap']
2812 self.assertEquals(orig_entry.offset, entry.offset)
2813 self.assertEquals(orig_entry.size, entry.size)
2814 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2815
2816 def testReadImageNoHeader(self):
2817 """Test accessing an image's FDT map without an image header"""
2818 self._CheckLz4()
2819 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002820 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002821 image = Image.FromFile(image_fname)
2822 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002823 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002824
2825 def testReadImageFail(self):
2826 """Test failing to read an image image's FDT map"""
2827 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002828 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002829 with self.assertRaises(ValueError) as e:
2830 image = Image.FromFile(image_fname)
2831 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002832
Simon Glass61f564d2019-07-08 14:25:48 -06002833 def testListCmd(self):
2834 """Test listing the files in an image using an Fdtmap"""
2835 self._CheckLz4()
2836 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2837
2838 # lz4 compression size differs depending on the version
2839 image = control.images['image']
2840 entries = image.GetEntries()
2841 section_size = entries['section'].size
2842 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2843 fdtmap_offset = entries['fdtmap'].offset
2844
Simon Glassf86a7362019-07-20 12:24:10 -06002845 try:
2846 tmpdir, updated_fname = self._SetupImageInTmpdir()
2847 with test_util.capture_sys_output() as (stdout, stderr):
2848 self._DoBinman('ls', '-i', updated_fname)
2849 finally:
2850 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002851 lines = stdout.getvalue().splitlines()
2852 expected = [
2853'Name Image-pos Size Entry-type Offset Uncomp-size',
2854'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002855'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002856' u-boot 0 4 u-boot 0',
2857' section 100 %x section 100' % section_size,
2858' cbfs 100 400 cbfs 0',
Simon Glassab326012023-10-14 14:40:28 -06002859' u-boot 120 4 u-boot 20',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002860' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002861' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002862' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002863 (fdtmap_offset, fdtmap_offset),
2864' image-header bf8 8 image-header bf8',
2865 ]
2866 self.assertEqual(expected, lines)
2867
2868 def testListCmdFail(self):
2869 """Test failing to list an image"""
2870 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002871 try:
2872 tmpdir, updated_fname = self._SetupImageInTmpdir()
2873 with self.assertRaises(ValueError) as e:
2874 self._DoBinman('ls', '-i', updated_fname)
2875 finally:
2876 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002877 self.assertIn("Cannot find FDT map in image", str(e.exception))
2878
2879 def _RunListCmd(self, paths, expected):
2880 """List out entries and check the result
2881
2882 Args:
2883 paths: List of paths to pass to the list command
2884 expected: Expected list of filenames to be returned, in order
2885 """
2886 self._CheckLz4()
2887 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002888 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002889 image = Image.FromFile(image_fname)
2890 lines = image.GetListEntries(paths)[1]
2891 files = [line[0].strip() for line in lines[1:]]
2892 self.assertEqual(expected, files)
2893
2894 def testListCmdSection(self):
2895 """Test listing the files in a section"""
2896 self._RunListCmd(['section'],
2897 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2898
2899 def testListCmdFile(self):
2900 """Test listing a particular file"""
2901 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2902
2903 def testListCmdWildcard(self):
2904 """Test listing a wildcarded file"""
2905 self._RunListCmd(['*boot*'],
2906 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2907
2908 def testListCmdWildcardMulti(self):
2909 """Test listing a wildcarded file"""
2910 self._RunListCmd(['*cb*', '*head*'],
2911 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2912
2913 def testListCmdEmpty(self):
2914 """Test listing a wildcarded file"""
2915 self._RunListCmd(['nothing'], [])
2916
2917 def testListCmdPath(self):
2918 """Test listing the files in a sub-entry of a section"""
2919 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2920
Simon Glassf667e452019-07-08 14:25:50 -06002921 def _RunExtractCmd(self, entry_name, decomp=True):
2922 """Extract an entry from an image
2923
2924 Args:
2925 entry_name: Entry name to extract
2926 decomp: True to decompress the data if compressed, False to leave
2927 it in its raw uncompressed format
2928
2929 Returns:
2930 data from entry
2931 """
2932 self._CheckLz4()
2933 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002934 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002935 return control.ReadEntry(image_fname, entry_name, decomp)
2936
2937 def testExtractSimple(self):
2938 """Test extracting a single file"""
2939 data = self._RunExtractCmd('u-boot')
2940 self.assertEqual(U_BOOT_DATA, data)
2941
Simon Glass71ce0ba2019-07-08 14:25:52 -06002942 def testExtractSection(self):
2943 """Test extracting the files in a section"""
2944 data = self._RunExtractCmd('section')
2945 cbfs_data = data[:0x400]
2946 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002947 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002948 dtb_data = data[0x400:]
2949 dtb = self._decompress(dtb_data)
2950 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2951
2952 def testExtractCompressed(self):
2953 """Test extracting compressed data"""
2954 data = self._RunExtractCmd('section/u-boot-dtb')
2955 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2956
2957 def testExtractRaw(self):
2958 """Test extracting compressed data without decompressing it"""
2959 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2960 dtb = self._decompress(data)
2961 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2962
2963 def testExtractCbfs(self):
2964 """Test extracting CBFS data"""
2965 data = self._RunExtractCmd('section/cbfs/u-boot')
2966 self.assertEqual(U_BOOT_DATA, data)
2967
2968 def testExtractCbfsCompressed(self):
2969 """Test extracting CBFS compressed data"""
2970 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2971 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2972
2973 def testExtractCbfsRaw(self):
2974 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002975 bintool = self.comp_bintools['lzma_alone']
2976 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002977 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002978 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002979 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2980
Simon Glassf667e452019-07-08 14:25:50 -06002981 def testExtractBadEntry(self):
2982 """Test extracting a bad section path"""
2983 with self.assertRaises(ValueError) as e:
2984 self._RunExtractCmd('section/does-not-exist')
2985 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2986 str(e.exception))
2987
2988 def testExtractMissingFile(self):
2989 """Test extracting file that does not exist"""
2990 with self.assertRaises(IOError) as e:
2991 control.ReadEntry('missing-file', 'name')
2992
2993 def testExtractBadFile(self):
2994 """Test extracting an invalid file"""
2995 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002996 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002997 with self.assertRaises(ValueError) as e:
2998 control.ReadEntry(fname, 'name')
2999
Simon Glass71ce0ba2019-07-08 14:25:52 -06003000 def testExtractCmd(self):
3001 """Test extracting a file fron an image on the command line"""
3002 self._CheckLz4()
3003 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003004 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06003005 try:
3006 tmpdir, updated_fname = self._SetupImageInTmpdir()
3007 with test_util.capture_sys_output() as (stdout, stderr):
3008 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3009 '-f', fname)
3010 finally:
3011 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003012 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003013 self.assertEqual(U_BOOT_DATA, data)
3014
3015 def testExtractOneEntry(self):
3016 """Test extracting a single entry fron an image """
3017 self._CheckLz4()
3018 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003019 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003020 fname = os.path.join(self._indir, 'output.extact')
3021 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07003022 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003023 self.assertEqual(U_BOOT_DATA, data)
3024
3025 def _CheckExtractOutput(self, decomp):
3026 """Helper to test file output with and without decompression
3027
3028 Args:
3029 decomp: True to decompress entry data, False to output it raw
3030 """
3031 def _CheckPresent(entry_path, expect_data, expect_size=None):
3032 """Check and remove expected file
3033
3034 This checks the data/size of a file and removes the file both from
3035 the outfiles set and from the output directory. Once all files are
3036 processed, both the set and directory should be empty.
3037
3038 Args:
3039 entry_path: Entry path
3040 expect_data: Data to expect in file, or None to skip check
3041 expect_size: Size of data to expect in file, or None to skip
3042 """
3043 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003044 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003045 os.remove(path)
3046 if expect_data:
3047 self.assertEqual(expect_data, data)
3048 elif expect_size:
3049 self.assertEqual(expect_size, len(data))
3050 outfiles.remove(path)
3051
3052 def _CheckDirPresent(name):
3053 """Remove expected directory
3054
3055 This gives an error if the directory does not exist as expected
3056
3057 Args:
3058 name: Name of directory to remove
3059 """
3060 path = os.path.join(outdir, name)
3061 os.rmdir(path)
3062
3063 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003064 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003065 outdir = os.path.join(self._indir, 'extract')
3066 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3067
3068 # Create a set of all file that were output (should be 9)
3069 outfiles = set()
3070 for root, dirs, files in os.walk(outdir):
3071 outfiles |= set([os.path.join(root, fname) for fname in files])
3072 self.assertEqual(9, len(outfiles))
3073 self.assertEqual(9, len(einfos))
3074
3075 image = control.images['image']
3076 entries = image.GetEntries()
3077
3078 # Check the 9 files in various ways
3079 section = entries['section']
3080 section_entries = section.GetEntries()
3081 cbfs_entries = section_entries['cbfs'].GetEntries()
3082 _CheckPresent('u-boot', U_BOOT_DATA)
3083 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3084 dtb_len = EXTRACT_DTB_SIZE
3085 if not decomp:
3086 dtb_len = cbfs_entries['u-boot-dtb'].size
3087 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3088 if not decomp:
3089 dtb_len = section_entries['u-boot-dtb'].size
3090 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3091
3092 fdtmap = entries['fdtmap']
3093 _CheckPresent('fdtmap', fdtmap.data)
3094 hdr = entries['image-header']
3095 _CheckPresent('image-header', hdr.data)
3096
3097 _CheckPresent('section/root', section.data)
3098 cbfs = section_entries['cbfs']
3099 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003100 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003101 _CheckPresent('root', data)
3102
3103 # There should be no files left. Remove all the directories to check.
3104 # If there are any files/dirs remaining, one of these checks will fail.
3105 self.assertEqual(0, len(outfiles))
3106 _CheckDirPresent('section/cbfs')
3107 _CheckDirPresent('section')
3108 _CheckDirPresent('')
3109 self.assertFalse(os.path.exists(outdir))
3110
3111 def testExtractAllEntries(self):
3112 """Test extracting all entries"""
3113 self._CheckLz4()
3114 self._CheckExtractOutput(decomp=True)
3115
3116 def testExtractAllEntriesRaw(self):
3117 """Test extracting all entries without decompressing them"""
3118 self._CheckLz4()
3119 self._CheckExtractOutput(decomp=False)
3120
3121 def testExtractSelectedEntries(self):
3122 """Test extracting some entries"""
3123 self._CheckLz4()
3124 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003125 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003126 outdir = os.path.join(self._indir, 'extract')
3127 einfos = control.ExtractEntries(image_fname, None, outdir,
3128 ['*cb*', '*head*'])
3129
3130 # File output is tested by testExtractAllEntries(), so just check that
3131 # the expected entries are selected
3132 names = [einfo.name for einfo in einfos]
3133 self.assertEqual(names,
3134 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3135
3136 def testExtractNoEntryPaths(self):
3137 """Test extracting some entries"""
3138 self._CheckLz4()
3139 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003140 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003141 with self.assertRaises(ValueError) as e:
3142 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003143 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003144 str(e.exception))
3145
3146 def testExtractTooManyEntryPaths(self):
3147 """Test extracting some entries"""
3148 self._CheckLz4()
3149 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003150 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003151 with self.assertRaises(ValueError) as e:
3152 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003153 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003154 str(e.exception))
3155
Simon Glasse2705fa2019-07-08 14:25:53 -06003156 def testPackAlignSection(self):
3157 """Test that sections can have alignment"""
3158 self._DoReadFile('131_pack_align_section.dts')
3159
3160 self.assertIn('image', control.images)
3161 image = control.images['image']
3162 entries = image.GetEntries()
3163 self.assertEqual(3, len(entries))
3164
3165 # First u-boot
3166 self.assertIn('u-boot', entries)
3167 entry = entries['u-boot']
3168 self.assertEqual(0, entry.offset)
3169 self.assertEqual(0, entry.image_pos)
3170 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3171 self.assertEqual(len(U_BOOT_DATA), entry.size)
3172
3173 # Section0
3174 self.assertIn('section0', entries)
3175 section0 = entries['section0']
3176 self.assertEqual(0x10, section0.offset)
3177 self.assertEqual(0x10, section0.image_pos)
3178 self.assertEqual(len(U_BOOT_DATA), section0.size)
3179
3180 # Second u-boot
3181 section_entries = section0.GetEntries()
3182 self.assertIn('u-boot', section_entries)
3183 entry = section_entries['u-boot']
3184 self.assertEqual(0, entry.offset)
3185 self.assertEqual(0x10, entry.image_pos)
3186 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3187 self.assertEqual(len(U_BOOT_DATA), entry.size)
3188
3189 # Section1
3190 self.assertIn('section1', entries)
3191 section1 = entries['section1']
3192 self.assertEqual(0x14, section1.offset)
3193 self.assertEqual(0x14, section1.image_pos)
3194 self.assertEqual(0x20, section1.size)
3195
3196 # Second u-boot
3197 section_entries = section1.GetEntries()
3198 self.assertIn('u-boot', section_entries)
3199 entry = section_entries['u-boot']
3200 self.assertEqual(0, entry.offset)
3201 self.assertEqual(0x14, entry.image_pos)
3202 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3203 self.assertEqual(len(U_BOOT_DATA), entry.size)
3204
3205 # Section2
3206 self.assertIn('section2', section_entries)
3207 section2 = section_entries['section2']
3208 self.assertEqual(0x4, section2.offset)
3209 self.assertEqual(0x18, section2.image_pos)
3210 self.assertEqual(4, section2.size)
3211
3212 # Third u-boot
3213 section_entries = section2.GetEntries()
3214 self.assertIn('u-boot', section_entries)
3215 entry = section_entries['u-boot']
3216 self.assertEqual(0, entry.offset)
3217 self.assertEqual(0x18, entry.image_pos)
3218 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3219 self.assertEqual(len(U_BOOT_DATA), entry.size)
3220
Simon Glass51014aa2019-07-20 12:23:56 -06003221 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3222 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003223 """Replace an entry in an image
3224
3225 This writes the entry data to update it, then opens the updated file and
3226 returns the value that it now finds there.
3227
3228 Args:
3229 entry_name: Entry name to replace
3230 data: Data to replace it with
3231 decomp: True to compress the data if needed, False if data is
3232 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003233 allow_resize: True to allow entries to change size, False to raise
3234 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003235
3236 Returns:
3237 Tuple:
3238 data from entry
3239 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003240 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003241 """
Simon Glass51014aa2019-07-20 12:23:56 -06003242 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003243 update_dtb=True)[1]
3244
3245 self.assertIn('image', control.images)
3246 image = control.images['image']
3247 entries = image.GetEntries()
3248 orig_dtb_data = entries['u-boot-dtb'].data
3249 orig_fdtmap_data = entries['fdtmap'].data
3250
Simon Glassc1aa66e2022-01-29 14:14:04 -07003251 image_fname = tools.get_output_filename('image.bin')
3252 updated_fname = tools.get_output_filename('image-updated.bin')
3253 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003254 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3255 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003256 data = control.ReadEntry(updated_fname, entry_name, decomp)
3257
Simon Glass51014aa2019-07-20 12:23:56 -06003258 # The DT data should not change unless resized:
3259 if not allow_resize:
3260 new_dtb_data = entries['u-boot-dtb'].data
3261 self.assertEqual(new_dtb_data, orig_dtb_data)
3262 new_fdtmap_data = entries['fdtmap'].data
3263 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003264
Simon Glass51014aa2019-07-20 12:23:56 -06003265 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003266
3267 def testReplaceSimple(self):
3268 """Test replacing a single file"""
3269 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003270 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3271 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003272 self.assertEqual(expected, data)
3273
3274 # Test that the state looks right. There should be an FDT for the fdtmap
3275 # that we jsut read back in, and it should match what we find in the
3276 # 'control' tables. Checking for an FDT that does not exist should
3277 # return None.
3278 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003279 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003280 self.assertEqual(expected_fdtmap, fdtmap)
3281
3282 dtb = state.GetFdtForEtype('fdtmap')
3283 self.assertEqual(dtb.GetContents(), fdtmap)
3284
3285 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3286 self.assertIsNone(missing_path)
3287 self.assertIsNone(missing_fdtmap)
3288
3289 missing_dtb = state.GetFdtForEtype('missing')
3290 self.assertIsNone(missing_dtb)
3291
3292 self.assertEqual('/binman', state.fdt_path_prefix)
3293
3294 def testReplaceResizeFail(self):
3295 """Test replacing a file by something larger"""
3296 expected = U_BOOT_DATA + b'x'
3297 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003298 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3299 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003300 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3301 str(e.exception))
3302
3303 def testReplaceMulti(self):
3304 """Test replacing entry data where multiple images are generated"""
3305 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3306 update_dtb=True)[0]
3307 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003308 updated_fname = tools.get_output_filename('image-updated.bin')
3309 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003310 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003311 control.WriteEntry(updated_fname, entry_name, expected,
3312 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003313 data = control.ReadEntry(updated_fname, entry_name)
3314 self.assertEqual(expected, data)
3315
3316 # Check the state looks right.
3317 self.assertEqual('/binman/image', state.fdt_path_prefix)
3318
3319 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003320 image_fname = tools.get_output_filename('first-image.bin')
3321 updated_fname = tools.get_output_filename('first-updated.bin')
3322 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003323 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003324 control.WriteEntry(updated_fname, entry_name, expected,
3325 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003326 data = control.ReadEntry(updated_fname, entry_name)
3327 self.assertEqual(expected, data)
3328
3329 # Check the state looks right.
3330 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003331
Simon Glass12bb1a92019-07-20 12:23:51 -06003332 def testUpdateFdtAllRepack(self):
3333 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003334 self._SetupSplElf()
3335 self._SetupTplElf()
Simon Glass12bb1a92019-07-20 12:23:51 -06003336 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3337 SECTION_SIZE = 0x300
3338 DTB_SIZE = 602
3339 FDTMAP_SIZE = 608
3340 base_expected = {
3341 'offset': 0,
3342 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3343 'image-pos': 0,
3344 'section:offset': 0,
3345 'section:size': SECTION_SIZE,
3346 'section:image-pos': 0,
3347 'section/u-boot-dtb:offset': 4,
3348 'section/u-boot-dtb:size': 636,
3349 'section/u-boot-dtb:image-pos': 4,
3350 'u-boot-spl-dtb:offset': SECTION_SIZE,
3351 'u-boot-spl-dtb:size': DTB_SIZE,
3352 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3353 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3354 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3355 'u-boot-tpl-dtb:size': DTB_SIZE,
3356 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3357 'fdtmap:size': FDTMAP_SIZE,
3358 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3359 }
3360 main_expected = {
3361 'section:orig-size': SECTION_SIZE,
3362 'section/u-boot-dtb:orig-offset': 4,
3363 }
3364
3365 # We expect three device-tree files in the output, with the first one
3366 # within a fixed-size section.
3367 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3368 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3369 # main U-Boot tree. All three should have the same positions and offset
3370 # except that the main tree should include the main_expected properties
3371 start = 4
3372 for item in ['', 'spl', 'tpl', None]:
3373 if item is None:
3374 start += 16 # Move past fdtmap header
3375 dtb = fdt.Fdt.FromData(data[start:])
3376 dtb.Scan()
3377 props = self._GetPropTree(dtb,
3378 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3379 prefix='/' if item is None else '/binman/')
3380 expected = dict(base_expected)
3381 if item:
3382 expected[item] = 0
3383 else:
3384 # Main DTB and fdtdec should include the 'orig-' properties
3385 expected.update(main_expected)
3386 # Helpful for debugging:
3387 #for prop in sorted(props):
3388 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3389 self.assertEqual(expected, props)
3390 if item == '':
3391 start = SECTION_SIZE
3392 else:
3393 start += dtb._fdt_obj.totalsize()
3394
Simon Glasseba1f0c2019-07-20 12:23:55 -06003395 def testFdtmapHeaderMiddle(self):
3396 """Test an FDT map in the middle of an image when it should be at end"""
3397 with self.assertRaises(ValueError) as e:
3398 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3399 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3400 str(e.exception))
3401
3402 def testFdtmapHeaderStartBad(self):
3403 """Test an FDT map in middle of an image when it should be at start"""
3404 with self.assertRaises(ValueError) as e:
3405 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3406 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3407 str(e.exception))
3408
3409 def testFdtmapHeaderEndBad(self):
3410 """Test an FDT map at the start of an image when it should be at end"""
3411 with self.assertRaises(ValueError) as e:
3412 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3413 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3414 str(e.exception))
3415
3416 def testFdtmapHeaderNoSize(self):
3417 """Test an image header at the end of an image with undefined size"""
3418 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3419
Simon Glass51014aa2019-07-20 12:23:56 -06003420 def testReplaceResize(self):
3421 """Test replacing a single file in an entry with a larger file"""
3422 expected = U_BOOT_DATA + b'x'
3423 data, _, image = self._RunReplaceCmd('u-boot', expected,
3424 dts='139_replace_repack.dts')
3425 self.assertEqual(expected, data)
3426
3427 entries = image.GetEntries()
3428 dtb_data = entries['u-boot-dtb'].data
3429 dtb = fdt.Fdt.FromData(dtb_data)
3430 dtb.Scan()
3431
3432 # The u-boot section should now be larger in the dtb
3433 node = dtb.GetNode('/binman/u-boot')
3434 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3435
3436 # Same for the fdtmap
3437 fdata = entries['fdtmap'].data
3438 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3439 fdtb.Scan()
3440 fnode = fdtb.GetNode('/u-boot')
3441 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3442
3443 def testReplaceResizeNoRepack(self):
3444 """Test replacing an entry with a larger file when not allowed"""
3445 expected = U_BOOT_DATA + b'x'
3446 with self.assertRaises(ValueError) as e:
3447 self._RunReplaceCmd('u-boot', expected)
3448 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3449 str(e.exception))
3450
Simon Glass61ec04f2019-07-20 12:23:58 -06003451 def testEntryShrink(self):
3452 """Test contracting an entry after it is packed"""
3453 try:
3454 state.SetAllowEntryContraction(True)
3455 data = self._DoReadFileDtb('140_entry_shrink.dts',
3456 update_dtb=True)[0]
3457 finally:
3458 state.SetAllowEntryContraction(False)
3459 self.assertEqual(b'a', data[:1])
3460 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3461 self.assertEqual(b'a', data[-1:])
3462
3463 def testEntryShrinkFail(self):
3464 """Test not being allowed to contract an entry after it is packed"""
3465 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3466
3467 # In this case there is a spare byte at the end of the data. The size of
3468 # the contents is only 1 byte but we still have the size before it
3469 # shrunk.
3470 self.assertEqual(b'a\0', data[:2])
3471 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3472 self.assertEqual(b'a\0', data[-2:])
3473
Simon Glass27145fd2019-07-20 12:24:01 -06003474 def testDescriptorOffset(self):
3475 """Test that the Intel descriptor is always placed at at the start"""
3476 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3477 image = control.images['image']
3478 entries = image.GetEntries()
3479 desc = entries['intel-descriptor']
3480 self.assertEqual(0xff800000, desc.offset);
3481 self.assertEqual(0xff800000, desc.image_pos);
3482
Simon Glasseb0f4a42019-07-20 12:24:06 -06003483 def testReplaceCbfs(self):
3484 """Test replacing a single file in CBFS without changing the size"""
3485 self._CheckLz4()
3486 expected = b'x' * len(U_BOOT_DATA)
3487 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003488 updated_fname = tools.get_output_filename('image-updated.bin')
3489 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003490 entry_name = 'section/cbfs/u-boot'
3491 control.WriteEntry(updated_fname, entry_name, expected,
3492 allow_resize=True)
3493 data = control.ReadEntry(updated_fname, entry_name)
3494 self.assertEqual(expected, data)
3495
3496 def testReplaceResizeCbfs(self):
3497 """Test replacing a single file in CBFS with one of a different size"""
3498 self._CheckLz4()
3499 expected = U_BOOT_DATA + b'x'
3500 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003501 updated_fname = tools.get_output_filename('image-updated.bin')
3502 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003503 entry_name = 'section/cbfs/u-boot'
3504 control.WriteEntry(updated_fname, entry_name, expected,
3505 allow_resize=True)
3506 data = control.ReadEntry(updated_fname, entry_name)
3507 self.assertEqual(expected, data)
3508
Simon Glassa6cb9952019-07-20 12:24:15 -06003509 def _SetupForReplace(self):
3510 """Set up some files to use to replace entries
3511
3512 This generates an image, copies it to a new file, extracts all the files
3513 in it and updates some of them
3514
3515 Returns:
3516 List
3517 Image filename
3518 Output directory
3519 Expected values for updated entries, each a string
3520 """
3521 data = self._DoReadFileRealDtb('143_replace_all.dts')
3522
Simon Glassc1aa66e2022-01-29 14:14:04 -07003523 updated_fname = tools.get_output_filename('image-updated.bin')
3524 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003525
3526 outdir = os.path.join(self._indir, 'extract')
3527 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3528
3529 expected1 = b'x' + U_BOOT_DATA + b'y'
3530 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003531 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003532
3533 expected2 = b'a' + U_BOOT_DATA + b'b'
3534 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003535 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003536
3537 expected_text = b'not the same text'
3538 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003539 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003540
3541 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3542 dtb = fdt.FdtScan(dtb_fname)
3543 node = dtb.GetNode('/binman/text')
3544 node.AddString('my-property', 'the value')
3545 dtb.Sync(auto_resize=True)
3546 dtb.Flush()
3547
3548 return updated_fname, outdir, expected1, expected2, expected_text
3549
3550 def _CheckReplaceMultiple(self, entry_paths):
3551 """Handle replacing the contents of multiple entries
3552
3553 Args:
3554 entry_paths: List of entry paths to replace
3555
3556 Returns:
3557 List
3558 Dict of entries in the image:
3559 key: Entry name
3560 Value: Entry object
3561 Expected values for updated entries, each a string
3562 """
3563 updated_fname, outdir, expected1, expected2, expected_text = (
3564 self._SetupForReplace())
3565 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3566
3567 image = Image.FromFile(updated_fname)
3568 image.LoadData()
3569 return image.GetEntries(), expected1, expected2, expected_text
3570
3571 def testReplaceAll(self):
3572 """Test replacing the contents of all entries"""
3573 entries, expected1, expected2, expected_text = (
3574 self._CheckReplaceMultiple([]))
3575 data = entries['u-boot'].data
3576 self.assertEqual(expected1, data)
3577
3578 data = entries['u-boot2'].data
3579 self.assertEqual(expected2, data)
3580
3581 data = entries['text'].data
3582 self.assertEqual(expected_text, data)
3583
3584 # Check that the device tree is updated
3585 data = entries['u-boot-dtb'].data
3586 dtb = fdt.Fdt.FromData(data)
3587 dtb.Scan()
3588 node = dtb.GetNode('/binman/text')
3589 self.assertEqual('the value', node.props['my-property'].value)
3590
3591 def testReplaceSome(self):
3592 """Test replacing the contents of a few entries"""
3593 entries, expected1, expected2, expected_text = (
3594 self._CheckReplaceMultiple(['u-boot2', 'text']))
3595
3596 # This one should not change
3597 data = entries['u-boot'].data
3598 self.assertEqual(U_BOOT_DATA, data)
3599
3600 data = entries['u-boot2'].data
3601 self.assertEqual(expected2, data)
3602
3603 data = entries['text'].data
3604 self.assertEqual(expected_text, data)
3605
3606 def testReplaceCmd(self):
3607 """Test replacing a file fron an image on the command line"""
3608 self._DoReadFileRealDtb('143_replace_all.dts')
3609
3610 try:
3611 tmpdir, updated_fname = self._SetupImageInTmpdir()
3612
3613 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3614 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003615 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003616
3617 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003618 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003619 self.assertEqual(expected, data[:len(expected)])
3620 map_fname = os.path.join(tmpdir, 'image-updated.map')
3621 self.assertFalse(os.path.exists(map_fname))
3622 finally:
3623 shutil.rmtree(tmpdir)
3624
3625 def testReplaceCmdSome(self):
3626 """Test replacing some files fron an image on the command line"""
3627 updated_fname, outdir, expected1, expected2, expected_text = (
3628 self._SetupForReplace())
3629
3630 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3631 'u-boot2', 'text')
3632
Simon Glassc1aa66e2022-01-29 14:14:04 -07003633 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003634 image = Image.FromFile(updated_fname)
3635 image.LoadData()
3636 entries = image.GetEntries()
3637
3638 # This one should not change
3639 data = entries['u-boot'].data
3640 self.assertEqual(U_BOOT_DATA, data)
3641
3642 data = entries['u-boot2'].data
3643 self.assertEqual(expected2, data)
3644
3645 data = entries['text'].data
3646 self.assertEqual(expected_text, data)
3647
3648 def testReplaceMissing(self):
3649 """Test replacing entries where the file is missing"""
3650 updated_fname, outdir, expected1, expected2, expected_text = (
3651 self._SetupForReplace())
3652
3653 # Remove one of the files, to generate a warning
3654 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3655 os.remove(u_boot_fname1)
3656
3657 with test_util.capture_sys_output() as (stdout, stderr):
3658 control.ReplaceEntries(updated_fname, None, outdir, [])
3659 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003660 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003661
3662 def testReplaceCmdMap(self):
3663 """Test replacing a file fron an image on the command line"""
3664 self._DoReadFileRealDtb('143_replace_all.dts')
3665
3666 try:
3667 tmpdir, updated_fname = self._SetupImageInTmpdir()
3668
3669 fname = os.path.join(self._indir, 'update-u-boot.bin')
3670 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003671 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003672
3673 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3674 '-f', fname, '-m')
3675 map_fname = os.path.join(tmpdir, 'image-updated.map')
3676 self.assertTrue(os.path.exists(map_fname))
3677 finally:
3678 shutil.rmtree(tmpdir)
3679
3680 def testReplaceNoEntryPaths(self):
3681 """Test replacing an entry without an entry path"""
3682 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003683 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003684 with self.assertRaises(ValueError) as e:
3685 control.ReplaceEntries(image_fname, 'fname', None, [])
3686 self.assertIn('Must specify an entry path to read with -f',
3687 str(e.exception))
3688
3689 def testReplaceTooManyEntryPaths(self):
3690 """Test extracting some entries"""
3691 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003692 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003693 with self.assertRaises(ValueError) as e:
3694 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3695 self.assertIn('Must specify exactly one entry path to write with -f',
3696 str(e.exception))
3697
Simon Glass2250ee62019-08-24 07:22:48 -06003698 def testPackReset16(self):
3699 """Test that an image with an x86 reset16 region can be created"""
3700 data = self._DoReadFile('144_x86_reset16.dts')
3701 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3702
3703 def testPackReset16Spl(self):
3704 """Test that an image with an x86 reset16-spl region can be created"""
3705 data = self._DoReadFile('145_x86_reset16_spl.dts')
3706 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3707
3708 def testPackReset16Tpl(self):
3709 """Test that an image with an x86 reset16-tpl region can be created"""
3710 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3711 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3712
Simon Glass5af12072019-08-24 07:22:50 -06003713 def testPackIntelFit(self):
3714 """Test that an image with an Intel FIT and pointer can be created"""
3715 data = self._DoReadFile('147_intel_fit.dts')
3716 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3717 fit = data[16:32];
3718 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3719 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3720
3721 image = control.images['image']
3722 entries = image.GetEntries()
3723 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3724 self.assertEqual(expected_ptr, ptr)
3725
3726 def testPackIntelFitMissing(self):
3727 """Test detection of a FIT pointer with not FIT region"""
3728 with self.assertRaises(ValueError) as e:
3729 self._DoReadFile('148_intel_fit_missing.dts')
3730 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3731 str(e.exception))
3732
Simon Glass7c150132019-11-06 17:22:44 -07003733 def _CheckSymbolsTplSection(self, dts, expected_vals):
3734 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003735 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003736 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003737 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003738 self.assertEqual(expected1, data[:upto1])
3739
3740 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003741 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003742 self.assertEqual(expected2, data[upto1:upto2])
3743
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003744 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003745 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003746 self.assertEqual(expected3, data[upto2:upto3])
3747
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003748 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003749 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3750
3751 def testSymbolsTplSection(self):
3752 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3753 self._SetupSplElf('u_boot_binman_syms')
3754 self._SetupTplElf('u_boot_binman_syms')
3755 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003756 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003757
3758 def testSymbolsTplSectionX86(self):
3759 """Test binman can assign symbols in a section with end-at-4gb"""
3760 self._SetupSplElf('u_boot_binman_syms_x86')
3761 self._SetupTplElf('u_boot_binman_syms_x86')
3762 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003763 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003764 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003765
Simon Glassbf4d0e22019-08-24 07:23:03 -06003766 def testPackX86RomIfwiSectiom(self):
3767 """Test that a section can be placed in an IFWI region"""
3768 self._SetupIfwi('fitimage.bin')
3769 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3770 self._CheckIfwi(data)
3771
Simon Glassea0fff92019-08-24 07:23:07 -06003772 def testPackFspM(self):
3773 """Test that an image with a FSP memory-init binary can be created"""
3774 data = self._DoReadFile('152_intel_fsp_m.dts')
3775 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3776
Simon Glassbc6a88f2019-10-20 21:31:35 -06003777 def testPackFspS(self):
3778 """Test that an image with a FSP silicon-init binary can be created"""
3779 data = self._DoReadFile('153_intel_fsp_s.dts')
3780 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003781
Simon Glass998d1482019-10-20 21:31:36 -06003782 def testPackFspT(self):
3783 """Test that an image with a FSP temp-ram-init binary can be created"""
3784 data = self._DoReadFile('154_intel_fsp_t.dts')
3785 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3786
Simon Glass0dc706f2020-07-09 18:39:31 -06003787 def testMkimage(self):
3788 """Test using mkimage to build an image"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003789 self._SetupSplElf()
Simon Glass0dc706f2020-07-09 18:39:31 -06003790 data = self._DoReadFile('156_mkimage.dts')
3791
3792 # Just check that the data appears in the file somewhere
3793 self.assertIn(U_BOOT_SPL_DATA, data)
3794
Simon Glass4f9ee832022-01-09 20:14:09 -07003795 def testMkimageMissing(self):
3796 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003797 self._SetupSplElf()
Simon Glass4f9ee832022-01-09 20:14:09 -07003798 with test_util.capture_sys_output() as (_, stderr):
3799 self._DoTestFile('156_mkimage.dts',
3800 force_missing_bintools='mkimage')
3801 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003802 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003803
Simon Glassce867ad2020-07-09 18:39:36 -06003804 def testExtblob(self):
3805 """Test an image with an external blob"""
3806 data = self._DoReadFile('157_blob_ext.dts')
3807 self.assertEqual(REFCODE_DATA, data)
3808
3809 def testExtblobMissing(self):
3810 """Test an image with a missing external blob"""
3811 with self.assertRaises(ValueError) as e:
3812 self._DoReadFile('158_blob_ext_missing.dts')
3813 self.assertIn("Filename 'missing-file' not found in input path",
3814 str(e.exception))
3815
Simon Glass4f9f1052020-07-09 18:39:38 -06003816 def testExtblobMissingOk(self):
3817 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003818 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003819 ret = self._DoTestFile('158_blob_ext_missing.dts',
3820 allow_missing=True)
3821 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003822 err = stderr.getvalue()
Jonas Karlman8f452bc2023-07-18 20:34:39 +00003823 self.assertIn('(missing-file)', err)
Simon Glass193d3db2023-02-07 14:34:18 -07003824 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003825 self.assertIn('Some images are invalid', err)
3826
3827 def testExtblobMissingOkFlag(self):
3828 """Test an image with an missing external blob allowed with -W"""
3829 with test_util.capture_sys_output() as (stdout, stderr):
3830 ret = self._DoTestFile('158_blob_ext_missing.dts',
3831 allow_missing=True, ignore_missing=True)
3832 self.assertEqual(0, ret)
3833 err = stderr.getvalue()
Jonas Karlman8f452bc2023-07-18 20:34:39 +00003834 self.assertIn('(missing-file)', err)
Simon Glass193d3db2023-02-07 14:34:18 -07003835 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003836 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003837
3838 def testExtblobMissingOkSect(self):
3839 """Test an image with an missing external blob that is allowed"""
3840 with test_util.capture_sys_output() as (stdout, stderr):
3841 self._DoTestFile('159_blob_ext_missing_sect.dts',
3842 allow_missing=True)
3843 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003844 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003845
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003846 def testPackX86RomMeMissingDesc(self):
3847 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003848 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003849 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003850 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003851 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003852
3853 def testPackX86RomMissingIfwi(self):
3854 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3855 self._SetupIfwi('fitimage.bin')
3856 pathname = os.path.join(self._indir, 'fitimage.bin')
3857 os.remove(pathname)
3858 with test_util.capture_sys_output() as (stdout, stderr):
3859 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3860 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003861 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003862
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003863 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003864 """Test that zero-size overlapping regions are ignored"""
3865 self._DoTestFile('160_pack_overlap_zero.dts')
3866
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003867 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003868 # The data should be inside the FIT
3869 dtb = fdt.Fdt.FromData(fit_data)
3870 dtb.Scan()
3871 fnode = dtb.GetNode('/images/kernel')
3872 self.assertIn('data', fnode.props)
3873
3874 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003875 tools.write_file(fname, fit_data)
3876 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003877
3878 # Check a few features to make sure the plumbing works. We don't need
3879 # to test the operation of mkimage or dumpimage here. First convert the
3880 # output into a dict where the keys are the fields printed by dumpimage
3881 # and the values are a list of values for each field
3882 lines = out.splitlines()
3883
3884 # Converts "Compression: gzip compressed" into two groups:
3885 # 'Compression' and 'gzip compressed'
3886 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3887 vals = collections.defaultdict(list)
3888 for line in lines:
3889 mat = re_line.match(line)
3890 vals[mat.group(1)].append(mat.group(2))
3891
3892 self.assertEquals('FIT description: test-desc', lines[0])
3893 self.assertIn('Created:', lines[1])
3894 self.assertIn('Image 0 (kernel)', vals)
3895 self.assertIn('Hash value', vals)
3896 data_sizes = vals.get('Data Size')
3897 self.assertIsNotNone(data_sizes)
3898 self.assertEqual(2, len(data_sizes))
3899 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003900 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3901 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3902
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003903 # Check if entry listing correctly omits /images/
3904 image = control.images['image']
3905 fit_entry = image.GetEntries()['fit']
3906 subentries = list(fit_entry.GetEntries().keys())
3907 expected = ['kernel', 'fdt-1']
3908 self.assertEqual(expected, subentries)
3909
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003910 def testSimpleFit(self):
3911 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003912 self._SetupSplElf()
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003913 data = self._DoReadFile('161_fit.dts')
3914 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3915 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3916 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3917
3918 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3919
3920 def testSimpleFitExpandsSubentries(self):
3921 """Test that FIT images expand their subentries"""
3922 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3923 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3924 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3925 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3926
3927 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003928
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003929 def testSimpleFitImagePos(self):
3930 """Test that we have correct image-pos for FIT subentries"""
3931 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3932 update_dtb=True)
3933 dtb = fdt.Fdt(out_dtb_fname)
3934 dtb.Scan()
3935 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3936
Simon Glass38397d02022-03-05 20:19:01 -07003937 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003938 self.assertEqual({
3939 'image-pos': 0,
3940 'offset': 0,
3941 'size': 1890,
3942
3943 'u-boot:image-pos': 0,
3944 'u-boot:offset': 0,
3945 'u-boot:size': 4,
3946
3947 'fit:image-pos': 4,
3948 'fit:offset': 4,
3949 'fit:size': 1840,
3950
Simon Glass38397d02022-03-05 20:19:01 -07003951 'fit/images/kernel:image-pos': 304,
3952 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003953 'fit/images/kernel:size': 4,
3954
Simon Glass38397d02022-03-05 20:19:01 -07003955 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003956 'fit/images/kernel/u-boot:offset': 0,
3957 'fit/images/kernel/u-boot:size': 4,
3958
Simon Glass38397d02022-03-05 20:19:01 -07003959 'fit/images/fdt-1:image-pos': 552,
3960 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003961 'fit/images/fdt-1:size': 6,
3962
Simon Glass38397d02022-03-05 20:19:01 -07003963 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003964 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3965 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3966
3967 'u-boot-nodtb:image-pos': 1844,
3968 'u-boot-nodtb:offset': 1844,
3969 'u-boot-nodtb:size': 46,
3970 }, props)
3971
3972 # Actually check the data is where we think it is
3973 for node, expected in [
3974 ("u-boot", U_BOOT_DATA),
3975 ("fit/images/kernel", U_BOOT_DATA),
3976 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3977 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3978 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3979 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3980 ]:
3981 image_pos = props[f"{node}:image-pos"]
3982 size = props[f"{node}:size"]
3983 self.assertEqual(len(expected), size)
3984 self.assertEqual(expected, data[image_pos:image_pos+size])
3985
Simon Glassfdc34362020-07-09 18:39:45 -06003986 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003987 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003988 data = self._DoReadFile('162_fit_external.dts')
3989 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3990
Simon Glass8bc78b72022-01-09 20:13:39 -07003991 # Size of the external-data region as set up by mkimage
3992 external_data_size = len(U_BOOT_DATA) + 2
3993 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003994 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003995 len(U_BOOT_NODTB_DATA))
3996
Simon Glassfdc34362020-07-09 18:39:45 -06003997 # The data should be outside the FIT
3998 dtb = fdt.Fdt.FromData(fit_data)
3999 dtb.Scan()
4000 fnode = dtb.GetNode('/images/kernel')
4001 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07004002 self.assertEqual(len(U_BOOT_DATA),
4003 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4004 fit_pos = 0x400;
4005 self.assertEqual(
4006 fit_pos,
4007 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4008
4009 self.assertEquals(expected_size, len(data))
4010 actual_pos = len(U_BOOT_DATA) + fit_pos
4011 self.assertEqual(U_BOOT_DATA + b'aa',
4012 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06004013
Alper Nebi Yasak73092222022-02-08 01:08:08 +03004014 def testFitExternalImagePos(self):
4015 """Test that we have correct image-pos for external FIT subentries"""
4016 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4017 update_dtb=True)
4018 dtb = fdt.Fdt(out_dtb_fname)
4019 dtb.Scan()
4020 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4021
4022 self.assertEqual({
4023 'image-pos': 0,
4024 'offset': 0,
4025 'size': 1082,
4026
4027 'u-boot:image-pos': 0,
4028 'u-boot:offset': 0,
4029 'u-boot:size': 4,
4030
4031 'fit:size': 1032,
4032 'fit:offset': 4,
4033 'fit:image-pos': 4,
4034
4035 'fit/images/kernel:size': 4,
4036 'fit/images/kernel:offset': 1024,
4037 'fit/images/kernel:image-pos': 1028,
4038
4039 'fit/images/kernel/u-boot:size': 4,
4040 'fit/images/kernel/u-boot:offset': 0,
4041 'fit/images/kernel/u-boot:image-pos': 1028,
4042
4043 'fit/images/fdt-1:size': 2,
4044 'fit/images/fdt-1:offset': 1028,
4045 'fit/images/fdt-1:image-pos': 1032,
4046
4047 'fit/images/fdt-1/_testing:size': 2,
4048 'fit/images/fdt-1/_testing:offset': 0,
4049 'fit/images/fdt-1/_testing:image-pos': 1032,
4050
4051 'u-boot-nodtb:image-pos': 1036,
4052 'u-boot-nodtb:offset': 1036,
4053 'u-boot-nodtb:size': 46,
4054 }, props)
4055
4056 # Actually check the data is where we think it is
4057 for node, expected in [
4058 ("u-boot", U_BOOT_DATA),
4059 ("fit/images/kernel", U_BOOT_DATA),
4060 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4061 ("fit/images/fdt-1", b'aa'),
4062 ("fit/images/fdt-1/_testing", b'aa'),
4063 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4064 ]:
4065 image_pos = props[f"{node}:image-pos"]
4066 size = props[f"{node}:size"]
4067 self.assertEqual(len(expected), size)
4068 self.assertEqual(expected, data[image_pos:image_pos+size])
4069
Simon Glass4f9ee832022-01-09 20:14:09 -07004070 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004071 """Test that binman complains if mkimage is missing"""
4072 with self.assertRaises(ValueError) as e:
4073 self._DoTestFile('162_fit_external.dts',
4074 force_missing_bintools='mkimage')
4075 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4076 str(e.exception))
4077
4078 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004079 """Test that binman still produces a FIT image if mkimage is missing"""
4080 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004081 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004082 force_missing_bintools='mkimage')
4083 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004084 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004085
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004086 def testSectionIgnoreHashSignature(self):
4087 """Test that sections ignore hash, signature nodes for its data"""
4088 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4089 expected = (U_BOOT_DATA + U_BOOT_DATA)
4090 self.assertEqual(expected, data)
4091
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004092 def testPadInSections(self):
4093 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004094 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4095 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004096 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4097 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004098 U_BOOT_DATA)
4099 self.assertEqual(expected, data)
4100
Simon Glassf90d9062020-10-26 17:40:09 -06004101 dtb = fdt.Fdt(out_dtb_fname)
4102 dtb.Scan()
4103 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4104 expected = {
4105 'image-pos': 0,
4106 'offset': 0,
4107 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4108
4109 'section:image-pos': 0,
4110 'section:offset': 0,
4111 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4112
4113 'section/before:image-pos': 0,
4114 'section/before:offset': 0,
4115 'section/before:size': len(U_BOOT_DATA),
4116
4117 'section/u-boot:image-pos': 4,
4118 'section/u-boot:offset': 4,
4119 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4120
4121 'section/after:image-pos': 26,
4122 'section/after:offset': 26,
4123 'section/after:size': len(U_BOOT_DATA),
4124 }
4125 self.assertEqual(expected, props)
4126
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004127 def testFitImageSubentryAlignment(self):
4128 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004129 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004130 entry_args = {
4131 'test-id': TEXT_DATA,
4132 }
4133 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4134 entry_args=entry_args)
4135 dtb = fdt.Fdt.FromData(data)
4136 dtb.Scan()
4137
4138 node = dtb.GetNode('/images/kernel')
4139 data = dtb.GetProps(node)["data"].bytes
4140 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004141 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4142 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004143 self.assertEqual(expected, data)
4144
4145 node = dtb.GetNode('/images/fdt-1')
4146 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004147 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4148 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004149 U_BOOT_DTB_DATA)
4150 self.assertEqual(expected, data)
4151
4152 def testFitExtblobMissingOk(self):
4153 """Test a FIT with a missing external blob that is allowed"""
4154 with test_util.capture_sys_output() as (stdout, stderr):
4155 self._DoTestFile('168_fit_missing_blob.dts',
4156 allow_missing=True)
4157 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004158 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004159
Simon Glass3decfa32020-09-01 05:13:54 -06004160 def testBlobNamedByArgMissing(self):
4161 """Test handling of a missing entry arg"""
4162 with self.assertRaises(ValueError) as e:
4163 self._DoReadFile('068_blob_named_by_arg.dts')
4164 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4165 str(e.exception))
4166
Simon Glassdc2f81a2020-09-01 05:13:58 -06004167 def testPackBl31(self):
4168 """Test that an image with an ATF BL31 binary can be created"""
4169 data = self._DoReadFile('169_atf_bl31.dts')
4170 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4171
Samuel Holland18bd4552020-10-21 21:12:15 -05004172 def testPackScp(self):
4173 """Test that an image with an SCP binary can be created"""
4174 data = self._DoReadFile('172_scp.dts')
4175 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4176
Simon Glass6cf99532020-09-01 05:13:59 -06004177 def testFitFdt(self):
4178 """Test an image with an FIT with multiple FDT images"""
4179 def _CheckFdt(seq, expected_data):
4180 """Check the FDT nodes
4181
4182 Args:
4183 seq: Sequence number to check (0 or 1)
4184 expected_data: Expected contents of 'data' property
4185 """
4186 name = 'fdt-%d' % seq
4187 fnode = dtb.GetNode('/images/%s' % name)
4188 self.assertIsNotNone(fnode)
4189 self.assertEqual({'description','type', 'compression', 'data'},
4190 set(fnode.props.keys()))
4191 self.assertEqual(expected_data, fnode.props['data'].bytes)
4192 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4193 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004194 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004195
4196 def _CheckConfig(seq, expected_data):
4197 """Check the configuration nodes
4198
4199 Args:
4200 seq: Sequence number to check (0 or 1)
4201 expected_data: Expected contents of 'data' property
4202 """
4203 cnode = dtb.GetNode('/configurations')
4204 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004205 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004206
4207 name = 'config-%d' % seq
4208 fnode = dtb.GetNode('/configurations/%s' % name)
4209 self.assertIsNotNone(fnode)
4210 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4211 set(fnode.props.keys()))
4212 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4213 fnode.props['description'].value)
4214 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4215
4216 entry_args = {
4217 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004218 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004219 }
4220 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004221 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004222 entry_args=entry_args,
4223 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4224 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4225 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4226
4227 dtb = fdt.Fdt.FromData(fit_data)
4228 dtb.Scan()
4229 fnode = dtb.GetNode('/images/kernel')
4230 self.assertIn('data', fnode.props)
4231
4232 # Check all the properties in fdt-1 and fdt-2
4233 _CheckFdt(1, TEST_FDT1_DATA)
4234 _CheckFdt(2, TEST_FDT2_DATA)
4235
4236 # Check configurations
4237 _CheckConfig(1, TEST_FDT1_DATA)
4238 _CheckConfig(2, TEST_FDT2_DATA)
4239
4240 def testFitFdtMissingList(self):
4241 """Test handling of a missing 'of-list' entry arg"""
4242 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004243 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004244 self.assertIn("Generator node requires 'of-list' entry argument",
4245 str(e.exception))
4246
4247 def testFitFdtEmptyList(self):
4248 """Test handling of an empty 'of-list' entry arg"""
4249 entry_args = {
4250 'of-list': '',
4251 }
4252 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4253
4254 def testFitFdtMissingProp(self):
4255 """Test handling of a missing 'fit,fdt-list' property"""
4256 with self.assertRaises(ValueError) as e:
4257 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4258 self.assertIn("Generator node requires 'fit,fdt-list' property",
4259 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004260
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004261 def testFitFdtMissing(self):
4262 """Test handling of a missing 'default-dt' entry arg"""
4263 entry_args = {
4264 'of-list': 'test-fdt1 test-fdt2',
4265 }
4266 with self.assertRaises(ValueError) as e:
4267 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004268 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004269 entry_args=entry_args,
4270 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4271 self.assertIn("Generated 'default' node requires default-dt entry argument",
4272 str(e.exception))
4273
4274 def testFitFdtNotInList(self):
4275 """Test handling of a default-dt that is not in the of-list"""
4276 entry_args = {
4277 'of-list': 'test-fdt1 test-fdt2',
4278 'default-dt': 'test-fdt3',
4279 }
4280 with self.assertRaises(ValueError) as e:
4281 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004282 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004283 entry_args=entry_args,
4284 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4285 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4286 str(e.exception))
4287
Simon Glassb2381432020-09-06 10:39:09 -06004288 def testFitExtblobMissingHelp(self):
4289 """Test display of help messages when an external blob is missing"""
4290 control.missing_blob_help = control._ReadMissingBlobHelp()
4291 control.missing_blob_help['wibble'] = 'Wibble test'
4292 control.missing_blob_help['another'] = 'Another test'
4293 with test_util.capture_sys_output() as (stdout, stderr):
4294 self._DoTestFile('168_fit_missing_blob.dts',
4295 allow_missing=True)
4296 err = stderr.getvalue()
4297
4298 # We can get the tag from the name, the type or the missing-msg
4299 # property. Check all three.
4300 self.assertIn('You may need to build ARM Trusted', err)
4301 self.assertIn('Wibble test', err)
4302 self.assertIn('Another test', err)
4303
Simon Glass204aa782020-09-06 10:35:32 -06004304 def testMissingBlob(self):
4305 """Test handling of a blob containing a missing file"""
4306 with self.assertRaises(ValueError) as e:
4307 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4308 self.assertIn("Filename 'missing' not found in input path",
4309 str(e.exception))
4310
Simon Glassfb91d562020-09-06 10:35:33 -06004311 def testEnvironment(self):
4312 """Test adding a U-Boot environment"""
4313 data = self._DoReadFile('174_env.dts')
4314 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4315 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4316 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4317 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4318 env)
4319
4320 def testEnvironmentNoSize(self):
4321 """Test that a missing 'size' property is detected"""
4322 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004323 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004324 self.assertIn("'u-boot-env' entry must have a size property",
4325 str(e.exception))
4326
4327 def testEnvironmentTooSmall(self):
4328 """Test handling of an environment that does not fit"""
4329 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004330 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004331
4332 # checksum, start byte, environment with \0 terminator, final \0
4333 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4334 short = need - 0x8
4335 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4336 str(e.exception))
4337
Simon Glassf2c0dd82020-10-26 17:40:01 -06004338 def testSkipAtStart(self):
4339 """Test handling of skip-at-start section"""
4340 data = self._DoReadFile('177_skip_at_start.dts')
4341 self.assertEqual(U_BOOT_DATA, data)
4342
4343 image = control.images['image']
4344 entries = image.GetEntries()
4345 section = entries['section']
4346 self.assertEqual(0, section.offset)
4347 self.assertEqual(len(U_BOOT_DATA), section.size)
4348 self.assertEqual(U_BOOT_DATA, section.GetData())
4349
4350 entry = section.GetEntries()['u-boot']
4351 self.assertEqual(16, entry.offset)
4352 self.assertEqual(len(U_BOOT_DATA), entry.size)
4353 self.assertEqual(U_BOOT_DATA, entry.data)
4354
4355 def testSkipAtStartPad(self):
4356 """Test handling of skip-at-start section with padded entry"""
4357 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004358 before = tools.get_bytes(0, 8)
4359 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004360 all = before + U_BOOT_DATA + after
4361 self.assertEqual(all, data)
4362
4363 image = control.images['image']
4364 entries = image.GetEntries()
4365 section = entries['section']
4366 self.assertEqual(0, section.offset)
4367 self.assertEqual(len(all), section.size)
4368 self.assertEqual(all, section.GetData())
4369
4370 entry = section.GetEntries()['u-boot']
4371 self.assertEqual(16, entry.offset)
4372 self.assertEqual(len(all), entry.size)
4373 self.assertEqual(U_BOOT_DATA, entry.data)
4374
4375 def testSkipAtStartSectionPad(self):
4376 """Test handling of skip-at-start section with padding"""
4377 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004378 before = tools.get_bytes(0, 8)
4379 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004380 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004381 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004382
4383 image = control.images['image']
4384 entries = image.GetEntries()
4385 section = entries['section']
4386 self.assertEqual(0, section.offset)
4387 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004388 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004389 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004390
4391 entry = section.GetEntries()['u-boot']
4392 self.assertEqual(16, entry.offset)
4393 self.assertEqual(len(U_BOOT_DATA), entry.size)
4394 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004395
Simon Glass7d398bb2020-10-26 17:40:14 -06004396 def testSectionPad(self):
4397 """Testing padding with sections"""
4398 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004399 expected = (tools.get_bytes(ord('&'), 3) +
4400 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004401 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004402 tools.get_bytes(ord('!'), 1) +
4403 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004404 self.assertEqual(expected, data)
4405
4406 def testSectionAlign(self):
4407 """Testing alignment with sections"""
4408 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4409 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004410 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004411 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004412 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004413 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004414 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4415 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004416 self.assertEqual(expected, data)
4417
Simon Glass8f5ef892020-10-26 17:40:25 -06004418 def testCompressImage(self):
4419 """Test compression of the entire image"""
4420 self._CheckLz4()
4421 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4422 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4423 dtb = fdt.Fdt(out_dtb_fname)
4424 dtb.Scan()
4425 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4426 'uncomp-size'])
4427 orig = self._decompress(data)
4428 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4429
4430 # Do a sanity check on various fields
4431 image = control.images['image']
4432 entries = image.GetEntries()
4433 self.assertEqual(2, len(entries))
4434
4435 entry = entries['blob']
4436 self.assertEqual(COMPRESS_DATA, entry.data)
4437 self.assertEqual(len(COMPRESS_DATA), entry.size)
4438
4439 entry = entries['u-boot']
4440 self.assertEqual(U_BOOT_DATA, entry.data)
4441 self.assertEqual(len(U_BOOT_DATA), entry.size)
4442
4443 self.assertEqual(len(data), image.size)
4444 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4445 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4446 orig = self._decompress(image.data)
4447 self.assertEqual(orig, image.uncomp_data)
4448
4449 expected = {
4450 'blob:offset': 0,
4451 'blob:size': len(COMPRESS_DATA),
4452 'u-boot:offset': len(COMPRESS_DATA),
4453 'u-boot:size': len(U_BOOT_DATA),
4454 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4455 'offset': 0,
4456 'image-pos': 0,
4457 'size': len(data),
4458 }
4459 self.assertEqual(expected, props)
4460
4461 def testCompressImageLess(self):
4462 """Test compression where compression reduces the image size"""
4463 self._CheckLz4()
4464 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4465 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4466 dtb = fdt.Fdt(out_dtb_fname)
4467 dtb.Scan()
4468 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4469 'uncomp-size'])
4470 orig = self._decompress(data)
4471
4472 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4473
4474 # Do a sanity check on various fields
4475 image = control.images['image']
4476 entries = image.GetEntries()
4477 self.assertEqual(2, len(entries))
4478
4479 entry = entries['blob']
4480 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4481 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4482
4483 entry = entries['u-boot']
4484 self.assertEqual(U_BOOT_DATA, entry.data)
4485 self.assertEqual(len(U_BOOT_DATA), entry.size)
4486
4487 self.assertEqual(len(data), image.size)
4488 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4489 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4490 image.uncomp_size)
4491 orig = self._decompress(image.data)
4492 self.assertEqual(orig, image.uncomp_data)
4493
4494 expected = {
4495 'blob:offset': 0,
4496 'blob:size': len(COMPRESS_DATA_BIG),
4497 'u-boot:offset': len(COMPRESS_DATA_BIG),
4498 'u-boot:size': len(U_BOOT_DATA),
4499 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4500 'offset': 0,
4501 'image-pos': 0,
4502 'size': len(data),
4503 }
4504 self.assertEqual(expected, props)
4505
4506 def testCompressSectionSize(self):
4507 """Test compression of a section with a fixed size"""
4508 self._CheckLz4()
4509 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4510 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4511 dtb = fdt.Fdt(out_dtb_fname)
4512 dtb.Scan()
4513 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4514 'uncomp-size'])
4515 orig = self._decompress(data)
4516 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4517 expected = {
4518 'section/blob:offset': 0,
4519 'section/blob:size': len(COMPRESS_DATA),
4520 'section/u-boot:offset': len(COMPRESS_DATA),
4521 'section/u-boot:size': len(U_BOOT_DATA),
4522 'section:offset': 0,
4523 'section:image-pos': 0,
4524 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4525 'section:size': 0x30,
4526 'offset': 0,
4527 'image-pos': 0,
4528 'size': 0x30,
4529 }
4530 self.assertEqual(expected, props)
4531
4532 def testCompressSection(self):
4533 """Test compression of a section with no fixed size"""
4534 self._CheckLz4()
4535 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4536 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4537 dtb = fdt.Fdt(out_dtb_fname)
4538 dtb.Scan()
4539 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4540 'uncomp-size'])
4541 orig = self._decompress(data)
4542 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4543 expected = {
4544 'section/blob:offset': 0,
4545 'section/blob:size': len(COMPRESS_DATA),
4546 'section/u-boot:offset': len(COMPRESS_DATA),
4547 'section/u-boot:size': len(U_BOOT_DATA),
4548 'section:offset': 0,
4549 'section:image-pos': 0,
4550 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4551 'section:size': len(data),
4552 'offset': 0,
4553 'image-pos': 0,
4554 'size': len(data),
4555 }
4556 self.assertEqual(expected, props)
4557
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004558 def testLz4Missing(self):
4559 """Test that binman still produces an image if lz4 is missing"""
4560 with test_util.capture_sys_output() as (_, stderr):
4561 self._DoTestFile('185_compress_section.dts',
4562 force_missing_bintools='lz4')
4563 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004564 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004565
Simon Glass8f5ef892020-10-26 17:40:25 -06004566 def testCompressExtra(self):
4567 """Test compression of a section with no fixed size"""
4568 self._CheckLz4()
4569 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4570 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4571 dtb = fdt.Fdt(out_dtb_fname)
4572 dtb.Scan()
4573 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4574 'uncomp-size'])
4575
4576 base = data[len(U_BOOT_DATA):]
4577 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4578 rest = base[len(U_BOOT_DATA):]
4579
4580 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004581 bintool = self.comp_bintools['lz4']
4582 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004583 data1 = rest[:len(expect1)]
4584 section1 = self._decompress(data1)
4585 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004586 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4587 rest1 = rest[len(expect1):]
4588
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004589 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004590 data2 = rest1[:len(expect2)]
4591 section2 = self._decompress(data2)
4592 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004593 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4594 rest2 = rest1[len(expect2):]
4595
4596 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4597 len(expect2) + len(U_BOOT_DATA))
4598 #self.assertEquals(expect_size, len(data))
4599
4600 #self.assertEquals(U_BOOT_DATA, rest2)
4601
4602 self.maxDiff = None
4603 expected = {
4604 'u-boot:offset': 0,
4605 'u-boot:image-pos': 0,
4606 'u-boot:size': len(U_BOOT_DATA),
4607
4608 'base:offset': len(U_BOOT_DATA),
4609 'base:image-pos': len(U_BOOT_DATA),
4610 'base:size': len(data) - len(U_BOOT_DATA),
4611 'base/u-boot:offset': 0,
4612 'base/u-boot:image-pos': len(U_BOOT_DATA),
4613 'base/u-boot:size': len(U_BOOT_DATA),
4614 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4615 len(expect2),
4616 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4617 len(expect2),
4618 'base/u-boot2:size': len(U_BOOT_DATA),
4619
4620 'base/section:offset': len(U_BOOT_DATA),
4621 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4622 'base/section:size': len(expect1),
4623 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4624 'base/section/blob:offset': 0,
4625 'base/section/blob:size': len(COMPRESS_DATA),
4626 'base/section/u-boot:offset': len(COMPRESS_DATA),
4627 'base/section/u-boot:size': len(U_BOOT_DATA),
4628
4629 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4630 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4631 'base/section2:size': len(expect2),
4632 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4633 'base/section2/blob:offset': 0,
4634 'base/section2/blob:size': len(COMPRESS_DATA),
4635 'base/section2/blob2:offset': len(COMPRESS_DATA),
4636 'base/section2/blob2:size': len(COMPRESS_DATA),
4637
4638 'offset': 0,
4639 'image-pos': 0,
4640 'size': len(data),
4641 }
4642 self.assertEqual(expected, props)
4643
Simon Glass870a9ea2021-01-06 21:35:15 -07004644 def testSymbolsSubsection(self):
4645 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004646 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004647
Simon Glass939d1062021-01-06 21:35:16 -07004648 def testReadImageEntryArg(self):
4649 """Test reading an image that would need an entry arg to generate"""
4650 entry_args = {
4651 'cros-ec-rw-path': 'ecrw.bin',
4652 }
4653 data = self.data = self._DoReadFileDtb(
4654 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4655 entry_args=entry_args)
4656
Simon Glassc1aa66e2022-01-29 14:14:04 -07004657 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004658 orig_image = control.images['image']
4659
4660 # This should not generate an error about the missing 'cros-ec-rw-path'
4661 # since we are reading the image from a file. Compare with
4662 # testEntryArgsRequired()
4663 image = Image.FromFile(image_fname)
4664 self.assertEqual(orig_image.GetEntries().keys(),
4665 image.GetEntries().keys())
4666
Simon Glass6eb99322021-01-06 21:35:18 -07004667 def testFilesAlign(self):
4668 """Test alignment with files"""
4669 data = self._DoReadFile('190_files_align.dts')
4670
4671 # The first string is 15 bytes so will align to 16
4672 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4673 self.assertEqual(expect, data)
4674
Simon Glass5c6ba712021-01-06 21:35:19 -07004675 def testReadImageSkip(self):
4676 """Test reading an image and accessing its FDT map"""
4677 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004678 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004679 orig_image = control.images['image']
4680 image = Image.FromFile(image_fname)
4681 self.assertEqual(orig_image.GetEntries().keys(),
4682 image.GetEntries().keys())
4683
4684 orig_entry = orig_image.GetEntries()['fdtmap']
4685 entry = image.GetEntries()['fdtmap']
4686 self.assertEqual(orig_entry.offset, entry.offset)
4687 self.assertEqual(orig_entry.size, entry.size)
4688 self.assertEqual(16, entry.image_pos)
4689
4690 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4691
4692 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4693
Simon Glass77a64e02021-03-18 20:24:57 +13004694 def testTplNoDtb(self):
4695 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004696 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004697 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4698 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4699 data[:len(U_BOOT_TPL_NODTB_DATA)])
4700
Simon Glassd26efc82021-03-18 20:24:58 +13004701 def testTplBssPad(self):
4702 """Test that we can pad TPL's BSS with zeros"""
4703 # ELF file with a '__bss_size' symbol
4704 self._SetupTplElf()
4705 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004706 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004707 data)
4708
4709 def testTplBssPadMissing(self):
4710 """Test that a missing symbol is detected"""
4711 self._SetupTplElf('u_boot_ucode_ptr')
4712 with self.assertRaises(ValueError) as e:
4713 self._DoReadFile('193_tpl_bss_pad.dts')
4714 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4715 str(e.exception))
4716
Simon Glass06684922021-03-18 20:25:07 +13004717 def checkDtbSizes(self, data, pad_len, start):
4718 """Check the size arguments in a dtb embedded in an image
4719
4720 Args:
4721 data: The image data
4722 pad_len: Length of the pad section in the image, in bytes
4723 start: Start offset of the devicetree to examine, within the image
4724
4725 Returns:
4726 Size of the devicetree in bytes
4727 """
4728 dtb_data = data[start:]
4729 dtb = fdt.Fdt.FromData(dtb_data)
4730 fdt_size = dtb.GetFdtObj().totalsize()
4731 dtb.Scan()
4732 props = self._GetPropTree(dtb, 'size')
4733 self.assertEqual({
4734 'size': len(data),
4735 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4736 'u-boot-spl/u-boot-spl-dtb:size': 801,
4737 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4738 'u-boot-spl:size': 860,
4739 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4740 'u-boot/u-boot-dtb:size': 781,
4741 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4742 'u-boot:size': 827,
4743 }, props)
4744 return fdt_size
4745
4746 def testExpanded(self):
4747 """Test that an expanded entry type is selected when needed"""
4748 self._SetupSplElf()
4749 self._SetupTplElf()
4750
4751 # SPL has a devicetree, TPL does not
4752 entry_args = {
4753 'spl-dtb': '1',
4754 'spl-bss-pad': 'y',
4755 'tpl-dtb': '',
4756 }
4757 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4758 entry_args=entry_args)
4759 image = control.images['image']
4760 entries = image.GetEntries()
4761 self.assertEqual(3, len(entries))
4762
4763 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4764 self.assertIn('u-boot', entries)
4765 entry = entries['u-boot']
4766 self.assertEqual('u-boot-expanded', entry.etype)
4767 subent = entry.GetEntries()
4768 self.assertEqual(2, len(subent))
4769 self.assertIn('u-boot-nodtb', subent)
4770 self.assertIn('u-boot-dtb', subent)
4771
4772 # Second, u-boot-spl, which should be expanded into three parts
4773 self.assertIn('u-boot-spl', entries)
4774 entry = entries['u-boot-spl']
4775 self.assertEqual('u-boot-spl-expanded', entry.etype)
4776 subent = entry.GetEntries()
4777 self.assertEqual(3, len(subent))
4778 self.assertIn('u-boot-spl-nodtb', subent)
4779 self.assertIn('u-boot-spl-bss-pad', subent)
4780 self.assertIn('u-boot-spl-dtb', subent)
4781
4782 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4783 # devicetree
4784 self.assertIn('u-boot-tpl', entries)
4785 entry = entries['u-boot-tpl']
4786 self.assertEqual('u-boot-tpl', entry.etype)
4787 self.assertEqual(None, entry.GetEntries())
4788
4789 def testExpandedTpl(self):
4790 """Test that an expanded entry type is selected for TPL when needed"""
4791 self._SetupTplElf()
4792
4793 entry_args = {
4794 'tpl-bss-pad': 'y',
4795 'tpl-dtb': 'y',
4796 }
4797 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4798 entry_args=entry_args)
4799 image = control.images['image']
4800 entries = image.GetEntries()
4801 self.assertEqual(1, len(entries))
4802
4803 # We only have u-boot-tpl, which be expanded
4804 self.assertIn('u-boot-tpl', entries)
4805 entry = entries['u-boot-tpl']
4806 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4807 subent = entry.GetEntries()
4808 self.assertEqual(3, len(subent))
4809 self.assertIn('u-boot-tpl-nodtb', subent)
4810 self.assertIn('u-boot-tpl-bss-pad', subent)
4811 self.assertIn('u-boot-tpl-dtb', subent)
4812
4813 def testExpandedNoPad(self):
4814 """Test an expanded entry without BSS pad enabled"""
4815 self._SetupSplElf()
4816 self._SetupTplElf()
4817
4818 # SPL has a devicetree, TPL does not
4819 entry_args = {
4820 'spl-dtb': 'something',
4821 'spl-bss-pad': 'n',
4822 'tpl-dtb': '',
4823 }
4824 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4825 entry_args=entry_args)
4826 image = control.images['image']
4827 entries = image.GetEntries()
4828
4829 # Just check u-boot-spl, which should be expanded into two parts
4830 self.assertIn('u-boot-spl', entries)
4831 entry = entries['u-boot-spl']
4832 self.assertEqual('u-boot-spl-expanded', entry.etype)
4833 subent = entry.GetEntries()
4834 self.assertEqual(2, len(subent))
4835 self.assertIn('u-boot-spl-nodtb', subent)
4836 self.assertIn('u-boot-spl-dtb', subent)
4837
4838 def testExpandedTplNoPad(self):
4839 """Test that an expanded entry type with padding disabled in TPL"""
4840 self._SetupTplElf()
4841
4842 entry_args = {
4843 'tpl-bss-pad': '',
4844 'tpl-dtb': 'y',
4845 }
4846 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4847 entry_args=entry_args)
4848 image = control.images['image']
4849 entries = image.GetEntries()
4850 self.assertEqual(1, len(entries))
4851
4852 # We only have u-boot-tpl, which be expanded
4853 self.assertIn('u-boot-tpl', entries)
4854 entry = entries['u-boot-tpl']
4855 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4856 subent = entry.GetEntries()
4857 self.assertEqual(2, len(subent))
4858 self.assertIn('u-boot-tpl-nodtb', subent)
4859 self.assertIn('u-boot-tpl-dtb', subent)
4860
4861 def testFdtInclude(self):
4862 """Test that an Fdt is update within all binaries"""
4863 self._SetupSplElf()
4864 self._SetupTplElf()
4865
4866 # SPL has a devicetree, TPL does not
4867 self.maxDiff = None
4868 entry_args = {
4869 'spl-dtb': '1',
4870 'spl-bss-pad': 'y',
4871 'tpl-dtb': '',
4872 }
4873 # Build the image. It includes two separate devicetree binaries, each
4874 # with their own contents, but all contain the binman definition.
4875 data = self._DoReadFileDtb(
4876 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4877 update_dtb=True, entry_args=entry_args)[0]
4878 pad_len = 10
4879
4880 # Check the U-Boot dtb
4881 start = len(U_BOOT_NODTB_DATA)
4882 fdt_size = self.checkDtbSizes(data, pad_len, start)
4883
4884 # Now check SPL
4885 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4886 fdt_size = self.checkDtbSizes(data, pad_len, start)
4887
4888 # TPL has no devicetree
4889 start += fdt_size + len(U_BOOT_TPL_DATA)
4890 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004891
Simon Glass3d433382021-03-21 18:24:30 +13004892 def testSymbolsExpanded(self):
4893 """Test binman can assign symbols in expanded entries"""
4894 entry_args = {
4895 'spl-dtb': '1',
4896 }
4897 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4898 U_BOOT_SPL_DTB_DATA, 0x38,
4899 entry_args=entry_args, use_expanded=True)
4900
Simon Glass189f2912021-03-21 18:24:31 +13004901 def testCollection(self):
4902 """Test a collection"""
4903 data = self._DoReadFile('198_collection.dts')
4904 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004905 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4906 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004907 data)
4908
Simon Glass631f7522021-03-21 18:24:32 +13004909 def testCollectionSection(self):
4910 """Test a collection where a section must be built first"""
4911 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004912 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004913 # building the contents, producing an error is anything is still
4914 # missing.
4915 data = self._DoReadFile('199_collection_section.dts')
4916 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004917 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4918 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004919 data)
4920
Simon Glass5ff9fed2021-03-21 18:24:33 +13004921 def testAlignDefault(self):
4922 """Test that default alignment works on sections"""
4923 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004924 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004925 U_BOOT_DATA)
4926 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004927 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004928 # No alignment within the nested section
4929 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4930 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004931 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004932 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004933
Bin Meng4c4d6072021-05-10 20:23:33 +08004934 def testPackOpenSBI(self):
4935 """Test that an image with an OpenSBI binary can be created"""
4936 data = self._DoReadFile('201_opensbi.dts')
4937 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4938
Simon Glassc69d19c2021-07-06 10:36:37 -06004939 def testSectionsSingleThread(self):
4940 """Test sections without multithreading"""
4941 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004942 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4943 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4944 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004945 self.assertEqual(expected, data)
4946
4947 def testThreadTimeout(self):
4948 """Test handling a thread that takes too long"""
4949 with self.assertRaises(ValueError) as e:
4950 self._DoTestFile('202_section_timeout.dts',
4951 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004952 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004953
Simon Glass03ebc202021-07-06 10:36:41 -06004954 def testTiming(self):
4955 """Test output of timing information"""
4956 data = self._DoReadFile('055_sections.dts')
4957 with test_util.capture_sys_output() as (stdout, stderr):
4958 state.TimingShow()
4959 self.assertIn('read:', stdout.getvalue())
4960 self.assertIn('compress:', stdout.getvalue())
4961
Simon Glass0427bed2021-11-03 21:09:18 -06004962 def testUpdateFdtInElf(self):
4963 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004964 if not elf.ELF_TOOLS:
4965 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004966 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4967 outfile = os.path.join(self._indir, 'u-boot.out')
4968 begin_sym = 'dtb_embed_begin'
4969 end_sym = 'dtb_embed_end'
4970 retcode = self._DoTestFile(
4971 '060_fdt_update.dts', update_dtb=True,
4972 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4973 self.assertEqual(0, retcode)
4974
4975 # Check that the output file does in fact contact a dtb with the binman
4976 # definition in the correct place
4977 syms = elf.GetSymbolFileOffset(infile,
4978 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004979 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004980 dtb_data = data[syms['dtb_embed_begin'].offset:
4981 syms['dtb_embed_end'].offset]
4982
4983 dtb = fdt.Fdt.FromData(dtb_data)
4984 dtb.Scan()
4985 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4986 self.assertEqual({
4987 'image-pos': 0,
4988 'offset': 0,
4989 '_testing:offset': 32,
4990 '_testing:size': 2,
4991 '_testing:image-pos': 32,
4992 'section@0/u-boot:offset': 0,
4993 'section@0/u-boot:size': len(U_BOOT_DATA),
4994 'section@0/u-boot:image-pos': 0,
4995 'section@0:offset': 0,
4996 'section@0:size': 16,
4997 'section@0:image-pos': 0,
4998
4999 'section@1/u-boot:offset': 0,
5000 'section@1/u-boot:size': len(U_BOOT_DATA),
5001 'section@1/u-boot:image-pos': 16,
5002 'section@1:offset': 16,
5003 'section@1:size': 16,
5004 'section@1:image-pos': 16,
5005 'size': 40
5006 }, props)
5007
5008 def testUpdateFdtInElfInvalid(self):
5009 """Test that invalid args are detected with --update-fdt-in-elf"""
5010 with self.assertRaises(ValueError) as e:
5011 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5012 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5013 str(e.exception))
5014
5015 def testUpdateFdtInElfNoSyms(self):
5016 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005017 if not elf.ELF_TOOLS:
5018 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005019 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5020 outfile = ''
5021 begin_sym = 'wrong_begin'
5022 end_sym = 'wrong_end'
5023 with self.assertRaises(ValueError) as e:
5024 self._DoTestFile(
5025 '060_fdt_update.dts',
5026 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5027 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5028 str(e.exception))
5029
5030 def testUpdateFdtInElfTooSmall(self):
5031 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005032 if not elf.ELF_TOOLS:
5033 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005034 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5035 outfile = os.path.join(self._indir, 'u-boot.out')
5036 begin_sym = 'dtb_embed_begin'
5037 end_sym = 'dtb_embed_end'
5038 with self.assertRaises(ValueError) as e:
5039 self._DoTestFile(
5040 '060_fdt_update.dts', update_dtb=True,
5041 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5042 self.assertRegex(
5043 str(e.exception),
5044 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5045
Simon Glassc475dec2021-11-23 11:03:42 -07005046 def testVersion(self):
5047 """Test we can get the binman version"""
5048 version = '(unreleased)'
5049 self.assertEqual(version, state.GetVersion(self._indir))
5050
5051 with self.assertRaises(SystemExit):
5052 with test_util.capture_sys_output() as (_, stderr):
5053 self._DoBinman('-V')
5054 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5055
5056 # Try running the tool too, just to be safe
5057 result = self._RunBinman('-V')
5058 self.assertEqual('Binman %s\n' % version, result.stderr)
5059
5060 # Set up a version file to make sure that works
5061 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07005062 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07005063 binary=False)
5064 self.assertEqual(version, state.GetVersion(self._indir))
5065
Simon Glass943bf782021-11-23 21:09:50 -07005066 def testAltFormat(self):
5067 """Test that alternative formats can be used to extract"""
5068 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5069
5070 try:
5071 tmpdir, updated_fname = self._SetupImageInTmpdir()
5072 with test_util.capture_sys_output() as (stdout, _):
5073 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5074 self.assertEqual(
5075 '''Flag (-F) Entry type Description
5076fdt fdtmap Extract the devicetree blob from the fdtmap
5077''',
5078 stdout.getvalue())
5079
5080 dtb = os.path.join(tmpdir, 'fdt.dtb')
5081 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5082 dtb, 'fdtmap')
5083
5084 # Check that we can read it and it can be scanning, meaning it does
5085 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005086 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005087 dtb = fdt.Fdt.FromData(data)
5088 dtb.Scan()
5089
5090 # Now check u-boot which has no alt_format
5091 fname = os.path.join(tmpdir, 'fdt.dtb')
5092 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5093 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005094 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005095 self.assertEqual(U_BOOT_DATA, data)
5096
5097 finally:
5098 shutil.rmtree(tmpdir)
5099
Simon Glasscc2c5002021-11-23 21:09:52 -07005100 def testExtblobList(self):
5101 """Test an image with an external blob list"""
5102 data = self._DoReadFile('215_blob_ext_list.dts')
5103 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5104
5105 def testExtblobListMissing(self):
5106 """Test an image with a missing external blob"""
5107 with self.assertRaises(ValueError) as e:
5108 self._DoReadFile('216_blob_ext_list_missing.dts')
5109 self.assertIn("Filename 'missing-file' not found in input path",
5110 str(e.exception))
5111
5112 def testExtblobListMissingOk(self):
5113 """Test an image with an missing external blob that is allowed"""
5114 with test_util.capture_sys_output() as (stdout, stderr):
5115 self._DoTestFile('216_blob_ext_list_missing.dts',
5116 allow_missing=True)
5117 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005118 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005119
Simon Glass75989722021-11-23 21:08:59 -07005120 def testFip(self):
5121 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5122 data = self._DoReadFile('203_fip.dts')
5123 hdr, fents = fip_util.decode_fip(data)
5124 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5125 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5126 self.assertEqual(0x123, hdr.flags)
5127
5128 self.assertEqual(2, len(fents))
5129
5130 fent = fents[0]
5131 self.assertEqual(
5132 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5133 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5134 self.assertEqual('soc-fw', fent.fip_type)
5135 self.assertEqual(0x88, fent.offset)
5136 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5137 self.assertEqual(0x123456789abcdef, fent.flags)
5138 self.assertEqual(ATF_BL31_DATA, fent.data)
5139 self.assertEqual(True, fent.valid)
5140
5141 fent = fents[1]
5142 self.assertEqual(
5143 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5144 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5145 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5146 self.assertEqual(0x8c, fent.offset)
5147 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5148 self.assertEqual(0, fent.flags)
5149 self.assertEqual(ATF_BL2U_DATA, fent.data)
5150 self.assertEqual(True, fent.valid)
5151
5152 def testFipOther(self):
5153 """Basic FIP with something that isn't a external blob"""
5154 data = self._DoReadFile('204_fip_other.dts')
5155 hdr, fents = fip_util.decode_fip(data)
5156
5157 self.assertEqual(2, len(fents))
5158 fent = fents[1]
5159 self.assertEqual('rot-cert', fent.fip_type)
5160 self.assertEqual(b'aa', fent.data)
5161
Simon Glass75989722021-11-23 21:08:59 -07005162 def testFipNoType(self):
5163 """FIP with an entry of an unknown type"""
5164 with self.assertRaises(ValueError) as e:
5165 self._DoReadFile('205_fip_no_type.dts')
5166 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5167 str(e.exception))
5168
5169 def testFipUuid(self):
5170 """Basic FIP with a manual uuid"""
5171 data = self._DoReadFile('206_fip_uuid.dts')
5172 hdr, fents = fip_util.decode_fip(data)
5173
5174 self.assertEqual(2, len(fents))
5175 fent = fents[1]
5176 self.assertEqual(None, fent.fip_type)
5177 self.assertEqual(
5178 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5179 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5180 fent.uuid)
5181 self.assertEqual(U_BOOT_DATA, fent.data)
5182
5183 def testFipLs(self):
5184 """Test listing a FIP"""
5185 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5186 hdr, fents = fip_util.decode_fip(data)
5187
5188 try:
5189 tmpdir, updated_fname = self._SetupImageInTmpdir()
5190 with test_util.capture_sys_output() as (stdout, stderr):
5191 self._DoBinman('ls', '-i', updated_fname)
5192 finally:
5193 shutil.rmtree(tmpdir)
5194 lines = stdout.getvalue().splitlines()
5195 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005196'Name Image-pos Size Entry-type Offset Uncomp-size',
5197'--------------------------------------------------------------',
5198'image 0 2d3 section 0',
5199' atf-fip 0 90 atf-fip 0',
5200' soc-fw 88 4 blob-ext 88',
5201' u-boot 8c 4 u-boot 8c',
5202' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005203]
5204 self.assertEqual(expected, lines)
5205
5206 image = control.images['image']
5207 entries = image.GetEntries()
5208 fdtmap = entries['fdtmap']
5209
5210 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5211 magic = fdtmap_data[:8]
5212 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005213 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005214
5215 fdt_data = fdtmap_data[16:]
5216 dtb = fdt.Fdt.FromData(fdt_data)
5217 dtb.Scan()
5218 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5219 self.assertEqual({
5220 'atf-fip/soc-fw:image-pos': 136,
5221 'atf-fip/soc-fw:offset': 136,
5222 'atf-fip/soc-fw:size': 4,
5223 'atf-fip/u-boot:image-pos': 140,
5224 'atf-fip/u-boot:offset': 140,
5225 'atf-fip/u-boot:size': 4,
5226 'atf-fip:image-pos': 0,
5227 'atf-fip:offset': 0,
5228 'atf-fip:size': 144,
5229 'image-pos': 0,
5230 'offset': 0,
5231 'fdtmap:image-pos': fdtmap.image_pos,
5232 'fdtmap:offset': fdtmap.offset,
5233 'fdtmap:size': len(fdtmap_data),
5234 'size': len(data),
5235 }, props)
5236
5237 def testFipExtractOneEntry(self):
5238 """Test extracting a single entry fron an FIP"""
5239 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005240 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005241 fname = os.path.join(self._indir, 'output.extact')
5242 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005243 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005244 self.assertEqual(U_BOOT_DATA, data)
5245
5246 def testFipReplace(self):
5247 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005248 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005249 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005250 updated_fname = tools.get_output_filename('image-updated.bin')
5251 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005252 entry_name = 'atf-fip/u-boot'
5253 control.WriteEntry(updated_fname, entry_name, expected,
5254 allow_resize=True)
5255 actual = control.ReadEntry(updated_fname, entry_name)
5256 self.assertEqual(expected, actual)
5257
Simon Glassc1aa66e2022-01-29 14:14:04 -07005258 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005259 hdr, fents = fip_util.decode_fip(new_data)
5260
5261 self.assertEqual(2, len(fents))
5262
5263 # Check that the FIP entry is updated
5264 fent = fents[1]
5265 self.assertEqual(0x8c, fent.offset)
5266 self.assertEqual(len(expected), fent.size)
5267 self.assertEqual(0, fent.flags)
5268 self.assertEqual(expected, fent.data)
5269 self.assertEqual(True, fent.valid)
5270
5271 def testFipMissing(self):
5272 with test_util.capture_sys_output() as (stdout, stderr):
5273 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5274 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005275 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005276
5277 def testFipSize(self):
5278 """Test a FIP with a size property"""
5279 data = self._DoReadFile('210_fip_size.dts')
5280 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5281 hdr, fents = fip_util.decode_fip(data)
5282 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5283 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5284
5285 self.assertEqual(1, len(fents))
5286
5287 fent = fents[0]
5288 self.assertEqual('soc-fw', fent.fip_type)
5289 self.assertEqual(0x60, fent.offset)
5290 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5291 self.assertEqual(ATF_BL31_DATA, fent.data)
5292 self.assertEqual(True, fent.valid)
5293
5294 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005295 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005296
5297 def testFipBadAlign(self):
5298 """Test that an invalid alignment value in a FIP is detected"""
5299 with self.assertRaises(ValueError) as e:
5300 self._DoTestFile('211_fip_bad_align.dts')
5301 self.assertIn(
5302 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5303 str(e.exception))
5304
5305 def testFipCollection(self):
5306 """Test using a FIP in a collection"""
5307 data = self._DoReadFile('212_fip_collection.dts')
5308 entry1 = control.images['image'].GetEntries()['collection']
5309 data1 = data[:entry1.size]
5310 hdr1, fents2 = fip_util.decode_fip(data1)
5311
5312 entry2 = control.images['image'].GetEntries()['atf-fip']
5313 data2 = data[entry2.offset:entry2.offset + entry2.size]
5314 hdr1, fents2 = fip_util.decode_fip(data2)
5315
5316 # The 'collection' entry should have U-Boot included at the end
5317 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5318 self.assertEqual(data1, data2 + U_BOOT_DATA)
5319 self.assertEqual(U_BOOT_DATA, data1[-4:])
5320
5321 # There should be a U-Boot after the final FIP
5322 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005323
Simon Glass32d4f102022-01-12 13:10:35 -07005324 def testFakeBlob(self):
5325 """Test handling of faking an external blob"""
5326 with test_util.capture_sys_output() as (stdout, stderr):
5327 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5328 allow_fake_blobs=True)
5329 err = stderr.getvalue()
5330 self.assertRegex(
5331 err,
5332 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005333
Simon Glassf4590e02022-01-09 20:13:46 -07005334 def testExtblobListFaked(self):
5335 """Test an extblob with missing external blob that are faked"""
5336 with test_util.capture_sys_output() as (stdout, stderr):
5337 self._DoTestFile('216_blob_ext_list_missing.dts',
5338 allow_fake_blobs=True)
5339 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005340 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005341
Simon Glass56ee85e2022-01-09 20:13:57 -07005342 def testListBintools(self):
5343 args = ['tool', '--list']
5344 with test_util.capture_sys_output() as (stdout, _):
5345 self._DoBinman(*args)
5346 out = stdout.getvalue().splitlines()
5347 self.assertTrue(len(out) >= 2)
5348
5349 def testFetchBintools(self):
5350 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005351 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005352 raise urllib.error.URLError('my error')
5353
5354 args = ['tool']
5355 with self.assertRaises(ValueError) as e:
5356 self._DoBinman(*args)
5357 self.assertIn("Invalid arguments to 'tool' subcommand",
5358 str(e.exception))
5359
5360 args = ['tool', '--fetch']
5361 with self.assertRaises(ValueError) as e:
5362 self._DoBinman(*args)
5363 self.assertIn('Please specify bintools to fetch', str(e.exception))
5364
5365 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005366 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005367 side_effect=fail_download):
5368 with test_util.capture_sys_output() as (stdout, _):
5369 self._DoBinman(*args)
5370 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5371
Simon Glassbc570642022-01-09 20:14:11 -07005372 def testBintoolDocs(self):
5373 """Test for creation of bintool documentation"""
5374 with test_util.capture_sys_output() as (stdout, stderr):
5375 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5376 self.assertTrue(len(stdout.getvalue()) > 0)
5377
5378 def testBintoolDocsMissing(self):
5379 """Test handling of missing bintool documentation"""
5380 with self.assertRaises(ValueError) as e:
5381 with test_util.capture_sys_output() as (stdout, stderr):
5382 control.write_bintool_docs(
5383 control.bintool.Bintool.get_tool_list(), 'mkimage')
5384 self.assertIn('Documentation is missing for modules: mkimage',
5385 str(e.exception))
5386
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005387 def testListWithGenNode(self):
5388 """Check handling of an FDT map when the section cannot be found"""
5389 entry_args = {
5390 'of-list': 'test-fdt1 test-fdt2',
5391 }
5392 data = self._DoReadFileDtb(
5393 '219_fit_gennode.dts',
5394 entry_args=entry_args,
5395 use_real_dtb=True,
5396 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5397
5398 try:
5399 tmpdir, updated_fname = self._SetupImageInTmpdir()
5400 with test_util.capture_sys_output() as (stdout, stderr):
5401 self._RunBinman('ls', '-i', updated_fname)
5402 finally:
5403 shutil.rmtree(tmpdir)
5404
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005405 def testFitSubentryUsesBintool(self):
5406 """Test that binman FIT subentries can use bintools"""
5407 command.test_result = self._HandleGbbCommand
5408 entry_args = {
5409 'keydir': 'devkeys',
5410 'bmpblk': 'bmpblk.bin',
5411 }
5412 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5413 entry_args=entry_args)
5414
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005415 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5416 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005417 self.assertIn(expected, data)
5418
5419 def testFitSubentryMissingBintool(self):
5420 """Test that binman reports missing bintools for FIT subentries"""
5421 entry_args = {
5422 'keydir': 'devkeys',
5423 }
5424 with test_util.capture_sys_output() as (_, stderr):
5425 self._DoTestFile('220_fit_subentry_bintool.dts',
5426 force_missing_bintools='futility', entry_args=entry_args)
5427 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005428 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005429
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005430 def testFitSubentryHashSubnode(self):
5431 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005432 self._SetupSplElf()
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005433 data, _, _, out_dtb_name = self._DoReadFileDtb(
5434 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5435
5436 mkimage_dtb = fdt.Fdt.FromData(data)
5437 mkimage_dtb.Scan()
5438 binman_dtb = fdt.Fdt(out_dtb_name)
5439 binman_dtb.Scan()
5440
5441 # Check that binman didn't add hash values
5442 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5443 self.assertNotIn('value', fnode.props)
5444
5445 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5446 self.assertNotIn('value', fnode.props)
5447
5448 # Check that mkimage added hash values
5449 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5450 self.assertIn('value', fnode.props)
5451
5452 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5453 self.assertIn('value', fnode.props)
5454
Roger Quadros47f420a2022-02-19 20:50:04 +02005455 def testPackTeeOs(self):
5456 """Test that an image with an TEE binary can be created"""
5457 data = self._DoReadFile('222_tee_os.dts')
5458 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5459
Neha Malcom Francis23d2ef92023-12-05 15:12:18 +05305460 def testPackTiDm(self):
5461 """Test that an image with a TI DM binary can be created"""
5462 data = self._DoReadFile('225_ti_dm.dts')
5463 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5464
Simon Glass6a0b5f82022-02-08 11:50:03 -07005465 def testFitFdtOper(self):
5466 """Check handling of a specified FIT operation"""
5467 entry_args = {
5468 'of-list': 'test-fdt1 test-fdt2',
5469 'default-dt': 'test-fdt2',
5470 }
5471 self._DoReadFileDtb(
5472 '223_fit_fdt_oper.dts',
5473 entry_args=entry_args,
5474 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5475
5476 def testFitFdtBadOper(self):
5477 """Check handling of an FDT map when the section cannot be found"""
5478 with self.assertRaises(ValueError) as exc:
5479 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005480 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005481 str(exc.exception))
5482
Simon Glass80a66ae2022-03-05 20:18:59 -07005483 def test_uses_expand_size(self):
5484 """Test that the 'expand-size' property cannot be used anymore"""
5485 with self.assertRaises(ValueError) as e:
5486 data = self._DoReadFile('225_expand_size_bad.dts')
5487 self.assertIn(
5488 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5489 str(e.exception))
5490
Simon Glass40c8bdd2022-03-05 20:19:12 -07005491 def testFitSplitElf(self):
5492 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005493 if not elf.ELF_TOOLS:
5494 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005495 entry_args = {
5496 'of-list': 'test-fdt1 test-fdt2',
5497 'default-dt': 'test-fdt2',
5498 'atf-bl31-path': 'bl31.elf',
5499 'tee-os-path': 'tee.elf',
5500 }
5501 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5502 data = self._DoReadFileDtb(
5503 '226_fit_split_elf.dts',
5504 entry_args=entry_args,
5505 extra_indirs=[test_subdir])[0]
5506
5507 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5508 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5509
5510 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5511 'data', 'load'}
5512 dtb = fdt.Fdt.FromData(fit_data)
5513 dtb.Scan()
5514
5515 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5516 segments, entry = elf.read_loadable_segments(elf_data)
5517
5518 # We assume there are two segments
5519 self.assertEquals(2, len(segments))
5520
5521 atf1 = dtb.GetNode('/images/atf-1')
5522 _, start, data = segments[0]
5523 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5524 self.assertEqual(entry,
5525 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5526 self.assertEqual(start,
5527 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5528 self.assertEqual(data, atf1.props['data'].bytes)
5529
Jonas Karlman00b3d532023-01-21 19:01:48 +00005530 hash_node = atf1.FindNode('hash')
5531 self.assertIsNotNone(hash_node)
5532 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5533
Simon Glass40c8bdd2022-03-05 20:19:12 -07005534 atf2 = dtb.GetNode('/images/atf-2')
5535 self.assertEqual(base_keys, atf2.props.keys())
5536 _, start, data = segments[1]
5537 self.assertEqual(start,
5538 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5539 self.assertEqual(data, atf2.props['data'].bytes)
5540
Jonas Karlman00b3d532023-01-21 19:01:48 +00005541 hash_node = atf2.FindNode('hash')
5542 self.assertIsNotNone(hash_node)
5543 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5544
5545 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5546 self.assertIsNotNone(hash_node)
5547 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5548
Simon Glass40c8bdd2022-03-05 20:19:12 -07005549 conf = dtb.GetNode('/configurations')
5550 self.assertEqual({'default'}, conf.props.keys())
5551
5552 for subnode in conf.subnodes:
5553 self.assertEqual({'description', 'fdt', 'loadables'},
5554 subnode.props.keys())
5555 self.assertEqual(
5556 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5557 fdt_util.GetStringList(subnode, 'loadables'))
5558
5559 def _check_bad_fit(self, dts):
5560 """Check a bad FIT
5561
5562 This runs with the given dts and returns the assertion raised
5563
5564 Args:
5565 dts (str): dts filename to use
5566
5567 Returns:
5568 str: Assertion string raised
5569 """
5570 entry_args = {
5571 'of-list': 'test-fdt1 test-fdt2',
5572 'default-dt': 'test-fdt2',
5573 'atf-bl31-path': 'bl31.elf',
5574 'tee-os-path': 'tee.elf',
5575 }
5576 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5577 with self.assertRaises(ValueError) as exc:
5578 self._DoReadFileDtb(dts, entry_args=entry_args,
5579 extra_indirs=[test_subdir])[0]
5580 return str(exc.exception)
5581
5582 def testFitSplitElfBadElf(self):
5583 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005584 if not elf.ELF_TOOLS:
5585 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005586 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5587 entry_args = {
5588 'of-list': 'test-fdt1 test-fdt2',
5589 'default-dt': 'test-fdt2',
5590 'atf-bl31-path': 'bad.elf',
5591 'tee-os-path': 'tee.elf',
5592 }
5593 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5594 with self.assertRaises(ValueError) as exc:
5595 self._DoReadFileDtb(
5596 '226_fit_split_elf.dts',
5597 entry_args=entry_args,
5598 extra_indirs=[test_subdir])[0]
5599 self.assertIn(
5600 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5601 str(exc.exception))
5602
Simon Glass40c8bdd2022-03-05 20:19:12 -07005603 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005604 """Test an split-elf FIT with a missing ELF file
5605
5606 Args:
5607 kwargs (dict of str): Arguments to pass to _DoTestFile()
5608
5609 Returns:
5610 tuple:
5611 str: stdout result
5612 str: stderr result
5613 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005614 entry_args = {
5615 'of-list': 'test-fdt1 test-fdt2',
5616 'default-dt': 'test-fdt2',
5617 'atf-bl31-path': 'bl31.elf',
5618 'tee-os-path': 'missing.elf',
5619 }
5620 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5621 with test_util.capture_sys_output() as (stdout, stderr):
5622 self._DoTestFile(
5623 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005624 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5625 out = stdout.getvalue()
5626 err = stderr.getvalue()
5627 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005628
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005629 def testFitSplitElfBadDirective(self):
5630 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5631 if not elf.ELF_TOOLS:
5632 self.skipTest('Python elftools not available')
5633 err = self._check_bad_fit('227_fit_bad_dir.dts')
5634 self.assertIn(
5635 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5636 err)
5637
5638 def testFitSplitElfBadDirectiveConfig(self):
5639 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5640 if not elf.ELF_TOOLS:
5641 self.skipTest('Python elftools not available')
5642 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5643 self.assertEqual(
5644 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5645 err)
5646
5647
Simon Glass40c8bdd2022-03-05 20:19:12 -07005648 def testFitSplitElfMissing(self):
5649 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005650 if not elf.ELF_TOOLS:
5651 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005652 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005653 self.assertRegex(
5654 err,
5655 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005656 self.assertNotRegex(out, '.*Faked blob.*')
5657 fname = tools.get_output_filename('binman-fake/missing.elf')
5658 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005659
5660 def testFitSplitElfFaked(self):
5661 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005662 if not elf.ELF_TOOLS:
5663 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005664 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005665 self.assertRegex(
5666 err,
5667 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005668 self.assertRegex(
5669 out,
5670 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5671 fname = tools.get_output_filename('binman-fake/missing.elf')
5672 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005673
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005674 def testMkimageMissingBlob(self):
5675 """Test using mkimage to build an image"""
5676 with test_util.capture_sys_output() as (stdout, stderr):
5677 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5678 allow_fake_blobs=True)
5679 err = stderr.getvalue()
5680 self.assertRegex(
5681 err,
5682 "Image '.*' has faked external blobs and is non-functional: .*")
5683
Philippe Reynesb1c50932022-03-28 22:57:04 +02005684 def testPreLoad(self):
5685 """Test an image with a pre-load header"""
5686 entry_args = {
Simon Glassefda8ab2023-07-24 09:19:57 -06005687 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesb1c50932022-03-28 22:57:04 +02005688 }
Simon Glassefda8ab2023-07-24 09:19:57 -06005689 data = self._DoReadFileDtb(
5690 '230_pre_load.dts', entry_args=entry_args,
5691 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005692 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5693 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5694 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5695
Simon Glassefda8ab2023-07-24 09:19:57 -06005696 def testPreLoadNoKey(self):
5697 """Test an image with a pre-load heade0r with missing key"""
5698 with self.assertRaises(FileNotFoundError) as exc:
5699 self._DoReadFile('230_pre_load.dts')
5700 self.assertIn("No such file or directory: 'dev.key'",
5701 str(exc.exception))
5702
Philippe Reynesb1c50932022-03-28 22:57:04 +02005703 def testPreLoadPkcs(self):
5704 """Test an image with a pre-load header with padding pkcs"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005705 entry_args = {
5706 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5707 }
5708 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5709 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005710 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5711 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5712 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5713
5714 def testPreLoadPss(self):
5715 """Test an image with a pre-load header with padding pss"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005716 entry_args = {
5717 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5718 }
5719 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5720 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005721 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5722 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5723 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5724
5725 def testPreLoadInvalidPadding(self):
5726 """Test an image with a pre-load header with an invalid padding"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005727 entry_args = {
5728 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5729 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005730 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005731 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5732 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005733
5734 def testPreLoadInvalidSha(self):
5735 """Test an image with a pre-load header with an invalid hash"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005736 entry_args = {
5737 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5738 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005739 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005740 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5741 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005742
5743 def testPreLoadInvalidAlgo(self):
5744 """Test an image with a pre-load header with an invalid algo"""
5745 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005746 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005747
5748 def testPreLoadInvalidKey(self):
5749 """Test an image with a pre-load header with an invalid key"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005750 entry_args = {
5751 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5752 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005753 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005754 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5755 entry_args=entry_args)
Roger Quadros47f420a2022-02-19 20:50:04 +02005756
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005757 def _CheckSafeUniqueNames(self, *images):
5758 """Check all entries of given images for unsafe unique names"""
5759 for image in images:
5760 entries = {}
5761 image._CollectEntries(entries, {}, image)
5762 for entry in entries.values():
5763 uniq = entry.GetUniqueName()
5764
5765 # Used as part of a filename, so must not be absolute paths.
5766 self.assertFalse(os.path.isabs(uniq))
5767
5768 def testSafeUniqueNames(self):
5769 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005770 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005771
5772 orig_image = control.images['image']
5773 image_fname = tools.get_output_filename('image.bin')
5774 image = Image.FromFile(image_fname)
5775
5776 self._CheckSafeUniqueNames(orig_image, image)
5777
5778 def testSafeUniqueNamesMulti(self):
5779 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005780 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005781
5782 orig_image = control.images['image']
5783 image_fname = tools.get_output_filename('image.bin')
5784 image = Image.FromFile(image_fname)
5785
5786 self._CheckSafeUniqueNames(orig_image, image)
5787
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005788 def testReplaceCmdWithBintool(self):
5789 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005790 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005791 expected = U_BOOT_DATA + b'aa'
5792 self.assertEqual(expected, data[:len(expected)])
5793
5794 try:
5795 tmpdir, updated_fname = self._SetupImageInTmpdir()
5796 fname = os.path.join(tmpdir, 'update-testing.bin')
5797 tools.write_file(fname, b'zz')
5798 self._DoBinman('replace', '-i', updated_fname,
5799 '_testing', '-f', fname)
5800
5801 data = tools.read_file(updated_fname)
5802 expected = U_BOOT_DATA + b'zz'
5803 self.assertEqual(expected, data[:len(expected)])
5804 finally:
5805 shutil.rmtree(tmpdir)
5806
5807 def testReplaceCmdOtherWithBintool(self):
5808 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005809 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005810 expected = U_BOOT_DATA + b'aa'
5811 self.assertEqual(expected, data[:len(expected)])
5812
5813 try:
5814 tmpdir, updated_fname = self._SetupImageInTmpdir()
5815 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5816 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5817 self._DoBinman('replace', '-i', updated_fname,
5818 'u-boot', '-f', fname)
5819
5820 data = tools.read_file(updated_fname)
5821 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5822 self.assertEqual(expected, data[:len(expected)])
5823 finally:
5824 shutil.rmtree(tmpdir)
5825
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005826 def testReplaceResizeNoRepackSameSize(self):
5827 """Test replacing entries with same-size data without repacking"""
5828 expected = b'x' * len(U_BOOT_DATA)
5829 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5830 self.assertEqual(expected, data)
5831
5832 path, fdtmap = state.GetFdtContents('fdtmap')
5833 self.assertIsNotNone(path)
5834 self.assertEqual(expected_fdtmap, fdtmap)
5835
5836 def testReplaceResizeNoRepackSmallerSize(self):
5837 """Test replacing entries with smaller-size data without repacking"""
5838 new_data = b'x'
5839 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5840 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5841 self.assertEqual(expected, data)
5842
5843 path, fdtmap = state.GetFdtContents('fdtmap')
5844 self.assertIsNotNone(path)
5845 self.assertEqual(expected_fdtmap, fdtmap)
5846
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005847 def testExtractFit(self):
5848 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005849 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005850 image_fname = tools.get_output_filename('image.bin')
5851
5852 fit_data = control.ReadEntry(image_fname, 'fit')
5853 fit = fdt.Fdt.FromData(fit_data)
5854 fit.Scan()
5855
5856 # Check subentry data inside the extracted fit
5857 for node_path, expected in [
5858 ('/images/kernel', U_BOOT_DATA),
5859 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5860 ('/images/scr-1', COMPRESS_DATA),
5861 ]:
5862 node = fit.GetNode(node_path)
5863 data = fit.GetProps(node)['data'].bytes
5864 self.assertEqual(expected, data)
5865
5866 def testExtractFitSubentries(self):
5867 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005868 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005869 image_fname = tools.get_output_filename('image.bin')
5870
5871 for entry_path, expected in [
5872 ('fit/kernel', U_BOOT_DATA),
5873 ('fit/kernel/u-boot', U_BOOT_DATA),
5874 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5875 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5876 ('fit/scr-1', COMPRESS_DATA),
5877 ('fit/scr-1/blob', COMPRESS_DATA),
5878 ]:
5879 data = control.ReadEntry(image_fname, entry_path)
5880 self.assertEqual(expected, data)
5881
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005882 def testReplaceFitSubentryLeafSameSize(self):
5883 """Test replacing a FIT leaf subentry with same-size data"""
5884 new_data = b'x' * len(U_BOOT_DATA)
5885 data, expected_fdtmap, _ = self._RunReplaceCmd(
5886 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005887 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005888 self.assertEqual(new_data, data)
5889
5890 path, fdtmap = state.GetFdtContents('fdtmap')
5891 self.assertIsNotNone(path)
5892 self.assertEqual(expected_fdtmap, fdtmap)
5893
5894 def testReplaceFitSubentryLeafBiggerSize(self):
5895 """Test replacing a FIT leaf subentry with bigger-size data"""
5896 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5897 data, expected_fdtmap, _ = self._RunReplaceCmd(
5898 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005899 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005900 self.assertEqual(new_data, data)
5901
5902 # Will be repacked, so fdtmap must change
5903 path, fdtmap = state.GetFdtContents('fdtmap')
5904 self.assertIsNotNone(path)
5905 self.assertNotEqual(expected_fdtmap, fdtmap)
5906
5907 def testReplaceFitSubentryLeafSmallerSize(self):
5908 """Test replacing a FIT leaf subentry with smaller-size data"""
5909 new_data = b'x'
5910 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5911 data, expected_fdtmap, _ = self._RunReplaceCmd(
5912 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005913 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005914 self.assertEqual(expected, data)
5915
5916 path, fdtmap = state.GetFdtContents('fdtmap')
5917 self.assertIsNotNone(path)
5918 self.assertEqual(expected_fdtmap, fdtmap)
5919
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005920 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005921 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005922 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005923 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5924 new_data, dts='241_replace_section_simple.dts')
5925 self.assertEqual(new_data, data)
5926
5927 entries = image.GetEntries()
5928 self.assertIn('section', entries)
5929 entry = entries['section']
5930 self.assertEqual(len(new_data), entry.size)
5931
5932 def testReplaceSectionLarger(self):
5933 """Test replacing a simple section with larger data"""
5934 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5935 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5936 new_data, dts='241_replace_section_simple.dts')
5937 self.assertEqual(new_data, data)
5938
5939 entries = image.GetEntries()
5940 self.assertIn('section', entries)
5941 entry = entries['section']
5942 self.assertEqual(len(new_data), entry.size)
5943 fentry = entries['fdtmap']
5944 self.assertEqual(entry.offset + entry.size, fentry.offset)
5945
5946 def testReplaceSectionSmaller(self):
5947 """Test replacing a simple section with smaller data"""
5948 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5949 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5950 new_data, dts='241_replace_section_simple.dts')
5951 self.assertEqual(new_data, data)
5952
5953 # The new size is the same as the old, just with a pad byte at the end
5954 entries = image.GetEntries()
5955 self.assertIn('section', entries)
5956 entry = entries['section']
5957 self.assertEqual(len(new_data), entry.size)
5958
5959 def testReplaceSectionSmallerAllow(self):
5960 """Test failing to replace a simple section with smaller data"""
5961 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5962 try:
5963 state.SetAllowEntryContraction(True)
5964 with self.assertRaises(ValueError) as exc:
5965 self._RunReplaceCmd('section', new_data,
5966 dts='241_replace_section_simple.dts')
5967 finally:
5968 state.SetAllowEntryContraction(False)
5969
5970 # Since we have no information about the position of things within the
5971 # section, we cannot adjust the position of /section-u-boot so it ends
5972 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005973 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005974 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5975 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005976 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005977
Simon Glassdfe1db42022-08-13 11:40:48 -06005978 def testMkimageImagename(self):
5979 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005980 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005981 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005982
5983 # Check that the data appears in the file somewhere
5984 self.assertIn(U_BOOT_SPL_DATA, data)
5985
Simon Glassf3543e62022-09-06 20:26:52 -06005986 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005987 name = data[0x20:0x40]
5988
5989 # Build the filename that we expect to be placed in there, by virtue of
5990 # the -n paraameter
5991 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5992
5993 # Check that the image name is set to the temporary filename used
5994 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5995
Simon Glass9db9e932022-08-13 11:40:49 -06005996 def testMkimageImage(self):
5997 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005998 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005999 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006000
6001 # Check that the data appears in the file somewhere
6002 self.assertIn(U_BOOT_SPL_DATA, data)
6003
Simon Glassf3543e62022-09-06 20:26:52 -06006004 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06006005 name = data[0x20:0x40]
6006
6007 # Build the filename that we expect to be placed in there, by virtue of
6008 # the -n paraameter
6009 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6010
6011 # Check that the image name is set to the temporary filename used
6012 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6013
6014 # Check the corect data is in the imagename file
6015 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6016
6017 def testMkimageImageNoContent(self):
6018 """Test using mkimage with -n and no data"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006019 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006020 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006021 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006022 self.assertIn('Could not complete processing of contents',
6023 str(exc.exception))
6024
6025 def testMkimageImageBad(self):
6026 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006027 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006028 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006029 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006030 self.assertIn('Cannot use both imagename node and data-to-imagename',
6031 str(exc.exception))
6032
Simon Glassd626e822022-08-13 11:40:50 -06006033 def testCollectionOther(self):
6034 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006035 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006036 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6037 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6038 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6039 data)
6040
6041 def testMkimageCollection(self):
6042 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006043 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006044 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006045 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6046 self.assertEqual(expect, data[:len(expect)])
6047
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006048 def testCompressDtbPrependInvalid(self):
6049 """Test that invalid header is detected"""
6050 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006051 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006052 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6053 "'u-boot-dtb': 'invalid'", str(e.exception))
6054
6055 def testCompressDtbPrependLength(self):
6056 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006057 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006058 image = control.images['image']
6059 entries = image.GetEntries()
6060 self.assertIn('u-boot-dtb', entries)
6061 u_boot_dtb = entries['u-boot-dtb']
6062 self.assertIn('fdtmap', entries)
6063 fdtmap = entries['fdtmap']
6064
6065 image_fname = tools.get_output_filename('image.bin')
6066 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6067 dtb = fdt.Fdt.FromData(orig)
6068 dtb.Scan()
6069 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6070 expected = {
6071 'u-boot:size': len(U_BOOT_DATA),
6072 'u-boot-dtb:uncomp-size': len(orig),
6073 'u-boot-dtb:size': u_boot_dtb.size,
6074 'fdtmap:size': fdtmap.size,
6075 'size': len(data),
6076 }
6077 self.assertEqual(expected, props)
6078
6079 # Check implementation
6080 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6081 rest = data[len(U_BOOT_DATA):]
6082 comp_data_len = struct.unpack('<I', rest[:4])[0]
6083 comp_data = rest[4:4 + comp_data_len]
6084 orig2 = self._decompress(comp_data)
6085 self.assertEqual(orig, orig2)
6086
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006087 def testInvalidCompress(self):
6088 """Test that invalid compress algorithm is detected"""
6089 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006090 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006091 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6092
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006093 def testCompUtilCompressions(self):
6094 """Test compression algorithms"""
6095 for bintool in self.comp_bintools.values():
6096 self._CheckBintool(bintool)
6097 data = bintool.compress(COMPRESS_DATA)
6098 self.assertNotEqual(COMPRESS_DATA, data)
6099 orig = bintool.decompress(data)
6100 self.assertEquals(COMPRESS_DATA, orig)
6101
6102 def testCompUtilVersions(self):
6103 """Test tool version of compression algorithms"""
6104 for bintool in self.comp_bintools.values():
6105 self._CheckBintool(bintool)
6106 version = bintool.version()
6107 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6108
6109 def testCompUtilPadding(self):
6110 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006111 # Skip zstd because it doesn't support padding
6112 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006113 self._CheckBintool(bintool)
6114 data = bintool.compress(COMPRESS_DATA)
6115 self.assertNotEqual(COMPRESS_DATA, data)
6116 data += tools.get_bytes(0, 64)
6117 orig = bintool.decompress(data)
6118 self.assertEquals(COMPRESS_DATA, orig)
6119
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006120 def testCompressDtbZstd(self):
6121 """Test that zstd compress of device-tree files failed"""
6122 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006123 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006124 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6125 "requires a length header", str(e.exception))
6126
Quentin Schulz4d91df02022-09-02 15:10:48 +02006127 def testMkimageMultipleDataFiles(self):
6128 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006129 self._SetupSplElf()
6130 self._SetupTplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006131 data = self._DoReadFile('252_mkimage_mult_data.dts')
6132 # Size of files are packed in their 4B big-endian format
6133 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6134 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6135 # Size info is always followed by a 4B zero value.
6136 expect += tools.get_bytes(0, 4)
6137 expect += U_BOOT_TPL_DATA
6138 # All but last files are 4B-aligned
6139 align_pad = len(U_BOOT_TPL_DATA) % 4
6140 if align_pad:
6141 expect += tools.get_bytes(0, align_pad)
6142 expect += U_BOOT_SPL_DATA
6143 self.assertEqual(expect, data[-len(expect):])
6144
Marek Vasutfadad3a2023-07-18 07:23:58 -06006145 def testMkimageMultipleExpanded(self):
6146 """Test passing multiple files to mkimage in a mkimage entry"""
6147 self._SetupSplElf()
6148 self._SetupTplElf()
6149 entry_args = {
6150 'spl-bss-pad': 'y',
6151 'spl-dtb': 'y',
6152 }
6153 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6154 use_expanded=True, entry_args=entry_args)[0]
6155 pad_len = 10
6156 tpl_expect = U_BOOT_TPL_DATA
6157 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6158 spl_expect += U_BOOT_SPL_DTB_DATA
6159
6160 content = data[0x40:]
6161 lens = struct.unpack('>III', content[:12])
6162
6163 # Size of files are packed in their 4B big-endian format
6164 # Size info is always followed by a 4B zero value.
6165 self.assertEqual(len(tpl_expect), lens[0])
6166 self.assertEqual(len(spl_expect), lens[1])
6167 self.assertEqual(0, lens[2])
6168
6169 rest = content[12:]
6170 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6171
6172 rest = rest[len(tpl_expect):]
6173 align_pad = len(tpl_expect) % 4
6174 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6175 rest = rest[align_pad:]
6176 self.assertEqual(spl_expect, rest)
6177
Quentin Schulz4d91df02022-09-02 15:10:48 +02006178 def testMkimageMultipleNoContent(self):
6179 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006180 self._SetupSplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006181 with self.assertRaises(ValueError) as exc:
6182 self._DoReadFile('253_mkimage_mult_no_content.dts')
6183 self.assertIn('Could not complete processing of contents',
6184 str(exc.exception))
6185
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006186 def testMkimageFilename(self):
6187 """Test using mkimage to build a binary with a filename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006188 self._SetupSplElf()
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006189 retcode = self._DoTestFile('254_mkimage_filename.dts')
6190 self.assertEqual(0, retcode)
6191 fname = tools.get_output_filename('mkimage-test.bin')
6192 self.assertTrue(os.path.exists(fname))
6193
Simon Glass6ad24522022-02-28 07:16:54 -07006194 def testVpl(self):
6195 """Test that an image with VPL and its device tree can be created"""
6196 # ELF file with a '__bss_size' symbol
6197 self._SetupVplElf()
6198 data = self._DoReadFile('255_u_boot_vpl.dts')
6199 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6200
6201 def testVplNoDtb(self):
6202 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6203 self._SetupVplElf()
6204 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6205 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6206 data[:len(U_BOOT_VPL_NODTB_DATA)])
6207
6208 def testExpandedVpl(self):
6209 """Test that an expanded entry type is selected for TPL when needed"""
6210 self._SetupVplElf()
6211
6212 entry_args = {
6213 'vpl-bss-pad': 'y',
6214 'vpl-dtb': 'y',
6215 }
6216 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6217 entry_args=entry_args)
6218 image = control.images['image']
6219 entries = image.GetEntries()
6220 self.assertEqual(1, len(entries))
6221
6222 # We only have u-boot-vpl, which be expanded
6223 self.assertIn('u-boot-vpl', entries)
6224 entry = entries['u-boot-vpl']
6225 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6226 subent = entry.GetEntries()
6227 self.assertEqual(3, len(subent))
6228 self.assertIn('u-boot-vpl-nodtb', subent)
6229 self.assertIn('u-boot-vpl-bss-pad', subent)
6230 self.assertIn('u-boot-vpl-dtb', subent)
6231
6232 def testVplBssPadMissing(self):
6233 """Test that a missing symbol is detected"""
6234 self._SetupVplElf('u_boot_ucode_ptr')
6235 with self.assertRaises(ValueError) as e:
6236 self._DoReadFile('258_vpl_bss_pad.dts')
6237 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6238 str(e.exception))
6239
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306240 def testSymlink(self):
Andrew Davis15432ea2023-07-22 00:14:44 +05306241 """Test that image files can be symlinked"""
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306242 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6243 self.assertEqual(0, retcode)
6244 image = control.images['test_image']
6245 fname = tools.get_output_filename('test_image.bin')
6246 sname = tools.get_output_filename('symlink_to_test.bin')
6247 self.assertTrue(os.path.islink(sname))
6248 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006249
Andrew Davis15432ea2023-07-22 00:14:44 +05306250 def testSymlinkOverwrite(self):
6251 """Test that symlinked images can be overwritten"""
6252 testdir = TestFunctional._MakeInputDir('symlinktest')
6253 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6254 # build the same image again in the same directory so that existing symlink is present
6255 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6256 fname = tools.get_output_filename('test_image.bin')
6257 sname = tools.get_output_filename('symlink_to_test.bin')
6258 self.assertTrue(os.path.islink(sname))
6259 self.assertEqual(os.readlink(sname), fname)
6260
Simon Glassd2afb9e2022-10-20 18:22:47 -06006261 def testSymbolsElf(self):
6262 """Test binman can assign symbols embedded in an ELF file"""
6263 if not elf.ELF_TOOLS:
6264 self.skipTest('Python elftools not available')
6265 self._SetupTplElf('u_boot_binman_syms')
6266 self._SetupVplElf('u_boot_binman_syms')
6267 self._SetupSplElf('u_boot_binman_syms')
6268 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6269 image_fname = tools.get_output_filename('image.bin')
6270
6271 image = control.images['image']
6272 entries = image.GetEntries()
6273
6274 for entry in entries.values():
6275 # No symbols in u-boot and it has faked contents anyway
6276 if entry.name == 'u-boot':
6277 continue
6278 edata = data[entry.image_pos:entry.image_pos + entry.size]
6279 efname = tools.get_output_filename(f'edata-{entry.name}')
6280 tools.write_file(efname, edata)
6281
6282 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6283 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6284 for name, sym in syms.items():
6285 msg = 'test'
6286 val = elf.GetSymbolValue(sym, edata, msg)
6287 entry_m = re_name.match(name)
6288 if entry_m:
6289 ename, prop = entry_m.group(1), entry_m.group(3)
6290 entry, entry_name, prop_name = image.LookupEntry(entries,
6291 name, msg)
6292 if prop_name == 'offset':
6293 expect_val = entry.offset
6294 elif prop_name == 'image_pos':
6295 expect_val = entry.image_pos
6296 elif prop_name == 'size':
6297 expect_val = entry.size
6298 self.assertEqual(expect_val, val)
6299
6300 def testSymbolsElfBad(self):
6301 """Check error when trying to write symbols without the elftools lib"""
6302 if not elf.ELF_TOOLS:
6303 self.skipTest('Python elftools not available')
6304 self._SetupTplElf('u_boot_binman_syms')
6305 self._SetupVplElf('u_boot_binman_syms')
6306 self._SetupSplElf('u_boot_binman_syms')
6307 try:
6308 elf.ELF_TOOLS = False
6309 with self.assertRaises(ValueError) as exc:
6310 self._DoReadFileDtb('260_symbols_elf.dts')
6311 finally:
6312 elf.ELF_TOOLS = True
6313 self.assertIn(
6314 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6315 'Cannot write symbols to an ELF file without Python elftools',
6316 str(exc.exception))
6317
Simon Glassefddab62023-01-07 14:07:08 -07006318 def testSectionFilename(self):
6319 """Check writing of section contents to a file"""
6320 data = self._DoReadFile('261_section_fname.dts')
6321 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6322 tools.get_bytes(ord('!'), 7) +
6323 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6324 self.assertEqual(expected, data)
6325
6326 sect_fname = tools.get_output_filename('outfile.bin')
6327 self.assertTrue(os.path.exists(sect_fname))
6328 sect_data = tools.read_file(sect_fname)
6329 self.assertEqual(U_BOOT_DATA, sect_data)
6330
Simon Glassc8c9f312023-01-07 14:07:12 -07006331 def testAbsent(self):
6332 """Check handling of absent entries"""
6333 data = self._DoReadFile('262_absent.dts')
6334 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6335
Simon Glass2f80c5e2023-01-07 14:07:14 -07006336 def testPackTeeOsOptional(self):
6337 """Test that an image with an optional TEE binary can be created"""
6338 entry_args = {
6339 'tee-os-path': 'tee.elf',
6340 }
6341 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6342 entry_args=entry_args)[0]
6343 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6344
6345 def checkFitTee(self, dts, tee_fname):
6346 """Check that a tee-os entry works and returns data
6347
6348 Args:
6349 dts (str): Device tree filename to use
6350 tee_fname (str): filename containing tee-os
6351
6352 Returns:
6353 bytes: Image contents
6354 """
6355 if not elf.ELF_TOOLS:
6356 self.skipTest('Python elftools not available')
6357 entry_args = {
6358 'of-list': 'test-fdt1 test-fdt2',
6359 'default-dt': 'test-fdt2',
6360 'tee-os-path': tee_fname,
6361 }
6362 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6363 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6364 extra_indirs=[test_subdir])[0]
6365 return data
6366
6367 def testFitTeeOsOptionalFit(self):
6368 """Test an image with a FIT with an optional OP-TEE binary"""
6369 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6370
6371 # There should be only one node, holding the data set up in SetUpClass()
6372 # for tee.bin
6373 dtb = fdt.Fdt.FromData(data)
6374 dtb.Scan()
6375 node = dtb.GetNode('/images/tee-1')
6376 self.assertEqual(TEE_ADDR,
6377 fdt_util.fdt32_to_cpu(node.props['load'].value))
6378 self.assertEqual(TEE_ADDR,
6379 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6380 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6381
Jonas Karlman49dcd1c2023-07-18 20:34:36 +00006382 with test_util.capture_sys_output() as (stdout, stderr):
6383 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6384 err = stderr.getvalue()
6385 self.assertRegex(
6386 err,
6387 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6388
Simon Glass2f80c5e2023-01-07 14:07:14 -07006389 def testFitTeeOsOptionalFitBad(self):
6390 """Test an image with a FIT with an optional OP-TEE binary"""
6391 with self.assertRaises(ValueError) as exc:
6392 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6393 self.assertIn(
6394 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6395 str(exc.exception))
6396
6397 def testFitTeeOsBad(self):
6398 """Test an OP-TEE binary with wrong formats"""
6399 self.make_tee_bin('tee.bad1', 123)
6400 with self.assertRaises(ValueError) as exc:
6401 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6402 self.assertIn(
6403 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6404 str(exc.exception))
6405
6406 self.make_tee_bin('tee.bad2', 0, b'extra data')
6407 with self.assertRaises(ValueError) as exc:
6408 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6409 self.assertIn(
6410 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6411 str(exc.exception))
6412
Simon Glass67a05012023-01-07 14:07:15 -07006413 def testExtblobOptional(self):
6414 """Test an image with an external blob that is optional"""
6415 with test_util.capture_sys_output() as (stdout, stderr):
6416 data = self._DoReadFile('266_blob_ext_opt.dts')
6417 self.assertEqual(REFCODE_DATA, data)
6418 err = stderr.getvalue()
6419 self.assertRegex(
6420 err,
Jonas Karlman05dec372023-07-18 20:34:34 +00006421 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass67a05012023-01-07 14:07:15 -07006422
Simon Glass0b079fc2023-01-11 16:10:12 -07006423 def testSectionInner(self):
6424 """Test an inner section with a size"""
6425 data = self._DoReadFile('267_section_inner.dts')
6426 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6427 self.assertEqual(expected, data)
6428
Simon Glass62ef2f72023-01-11 16:10:14 -07006429 def testNull(self):
6430 """Test an image with a null entry"""
6431 data = self._DoReadFile('268_null.dts')
6432 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6433
Simon Glass9766f692023-01-11 16:10:16 -07006434 def testOverlap(self):
6435 """Test an image with a overlapping entry"""
6436 data = self._DoReadFile('269_overlap.dts')
6437 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6438
6439 image = control.images['image']
6440 entries = image.GetEntries()
6441
6442 self.assertIn('inset', entries)
6443 inset = entries['inset']
6444 self.assertEqual(1, inset.offset);
6445 self.assertEqual(1, inset.image_pos);
6446 self.assertEqual(2, inset.size);
6447
6448 def testOverlapNull(self):
6449 """Test an image with a null overlap"""
6450 data = self._DoReadFile('270_overlap_null.dts')
6451 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6452
6453 # Check the FMAP
6454 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6455 self.assertEqual(4, fhdr.nareas)
6456 fiter = iter(fentries)
6457
6458 fentry = next(fiter)
6459 self.assertEqual(b'SECTION', fentry.name)
6460 self.assertEqual(0, fentry.offset)
6461 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6462 self.assertEqual(0, fentry.flags)
6463
6464 fentry = next(fiter)
6465 self.assertEqual(b'U_BOOT', fentry.name)
6466 self.assertEqual(0, fentry.offset)
6467 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6468 self.assertEqual(0, fentry.flags)
6469
6470 # Make sure that the NULL entry appears in the FMAP
6471 fentry = next(fiter)
6472 self.assertEqual(b'NULL', fentry.name)
6473 self.assertEqual(1, fentry.offset)
6474 self.assertEqual(2, fentry.size)
6475 self.assertEqual(0, fentry.flags)
6476
6477 fentry = next(fiter)
6478 self.assertEqual(b'FMAP', fentry.name)
6479 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6480
6481 def testOverlapBad(self):
6482 """Test an image with a bad overlapping entry"""
6483 with self.assertRaises(ValueError) as exc:
6484 self._DoReadFile('271_overlap_bad.dts')
6485 self.assertIn(
6486 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6487 str(exc.exception))
6488
6489 def testOverlapNoOffset(self):
6490 """Test an image with a bad overlapping entry"""
6491 with self.assertRaises(ValueError) as exc:
6492 self._DoReadFile('272_overlap_no_size.dts')
6493 self.assertIn(
6494 "Node '/binman/inset': 'fill' entry is missing properties: size",
6495 str(exc.exception))
6496
Simon Glassc1157862023-01-11 16:10:17 -07006497 def testBlobSymbol(self):
6498 """Test a blob with symbols read from an ELF file"""
6499 elf_fname = self.ElfTestFile('blob_syms')
6500 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6501 TestFunctional._MakeInputFile('blob_syms.bin',
6502 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6503
6504 data = self._DoReadFile('273_blob_symbol.dts')
6505
6506 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6507 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6508 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6509 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6510 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6511
6512 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6513 expected = sym_values
6514 self.assertEqual(expected, data[:len(expected)])
6515
Simon Glass571bc4e2023-01-11 16:10:19 -07006516 def testOffsetFromElf(self):
6517 """Test a blob with symbols read from an ELF file"""
6518 elf_fname = self.ElfTestFile('blob_syms')
6519 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6520 TestFunctional._MakeInputFile('blob_syms.bin',
6521 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6522
6523 data = self._DoReadFile('274_offset_from_elf.dts')
6524
6525 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6526 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6527
6528 image = control.images['image']
6529 entries = image.GetEntries()
6530
6531 self.assertIn('inset', entries)
6532 inset = entries['inset']
6533
6534 self.assertEqual(base + 4, inset.offset);
6535 self.assertEqual(base + 4, inset.image_pos);
6536 self.assertEqual(4, inset.size);
6537
6538 self.assertIn('inset2', entries)
6539 inset = entries['inset2']
6540 self.assertEqual(base + 8, inset.offset);
6541 self.assertEqual(base + 8, inset.image_pos);
6542 self.assertEqual(4, inset.size);
6543
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006544 def testFitAlign(self):
6545 """Test an image with an FIT with aligned external data"""
6546 data = self._DoReadFile('275_fit_align.dts')
6547 self.assertEqual(4096, len(data))
6548
6549 dtb = fdt.Fdt.FromData(data)
6550 dtb.Scan()
6551
6552 props = self._GetPropTree(dtb, ['data-position'])
6553 expected = {
6554 'u-boot:data-position': 1024,
6555 'fdt-1:data-position': 2048,
6556 'fdt-2:data-position': 3072,
6557 }
6558 self.assertEqual(expected, props)
6559
Jonas Karlmanf584d442023-01-21 19:02:12 +00006560 def testFitFirmwareLoadables(self):
6561 """Test an image with an FIT that use fit,firmware"""
6562 if not elf.ELF_TOOLS:
6563 self.skipTest('Python elftools not available')
6564 entry_args = {
6565 'of-list': 'test-fdt1',
6566 'default-dt': 'test-fdt1',
6567 'atf-bl31-path': 'bl31.elf',
6568 'tee-os-path': 'missing.bin',
6569 }
6570 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006571 with test_util.capture_sys_output() as (stdout, stderr):
6572 data = self._DoReadFileDtb(
6573 '276_fit_firmware_loadables.dts',
6574 entry_args=entry_args,
6575 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006576
6577 dtb = fdt.Fdt.FromData(data)
6578 dtb.Scan()
6579
6580 node = dtb.GetNode('/configurations/conf-uboot-1')
6581 self.assertEqual('u-boot', node.props['firmware'].value)
6582 self.assertEqual(['atf-1', 'atf-2'],
6583 fdt_util.GetStringList(node, 'loadables'))
6584
6585 node = dtb.GetNode('/configurations/conf-atf-1')
6586 self.assertEqual('atf-1', node.props['firmware'].value)
6587 self.assertEqual(['u-boot', 'atf-2'],
6588 fdt_util.GetStringList(node, 'loadables'))
6589
6590 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6591 self.assertEqual('u-boot', node.props['firmware'].value)
6592 self.assertEqual(['atf-1', 'atf-2'],
6593 fdt_util.GetStringList(node, 'loadables'))
6594
6595 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6596 self.assertEqual('atf-1', node.props['firmware'].value)
6597 self.assertEqual(['u-boot', 'atf-2'],
6598 fdt_util.GetStringList(node, 'loadables'))
6599
6600 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6601 self.assertEqual('atf-1', node.props['firmware'].value)
6602 self.assertEqual(['u-boot', 'atf-2'],
6603 fdt_util.GetStringList(node, 'loadables'))
6604
Simon Glassfe7e9242023-02-22 12:14:49 -07006605 def testTooldir(self):
6606 """Test that we can specify the tooldir"""
6607 with test_util.capture_sys_output() as (stdout, stderr):
6608 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6609 'tool', '-l'))
6610 self.assertEqual('fred', bintool.Bintool.tooldir)
6611
6612 # Check that the toolpath is updated correctly
6613 self.assertEqual(['fred'], tools.tool_search_paths)
6614
6615 # Try with a few toolpaths; the tooldir should be at the end
6616 with test_util.capture_sys_output() as (stdout, stderr):
6617 self.assertEqual(0, self._DoBinman(
6618 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6619 'tool', '-l'))
6620 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6621
Simon Glass7caa3722023-03-02 17:02:44 -07006622 def testReplaceSectionEntry(self):
6623 """Test replacing an entry in a section"""
6624 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6625 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6626 expect_data, dts='241_replace_section_simple.dts')
6627 self.assertEqual(expect_data, entry_data)
6628
6629 entries = image.GetEntries()
6630 self.assertIn('section', entries)
6631 section = entries['section']
6632
6633 sect_entries = section.GetEntries()
6634 self.assertIn('blob', sect_entries)
6635 entry = sect_entries['blob']
6636 self.assertEqual(len(expect_data), entry.size)
6637
6638 fname = tools.get_output_filename('image-updated.bin')
6639 data = tools.read_file(fname)
6640
6641 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6642 self.assertEqual(expect_data, new_blob_data)
6643
6644 self.assertEqual(U_BOOT_DATA,
6645 data[entry.image_pos + len(expect_data):]
6646 [:len(U_BOOT_DATA)])
6647
6648 def testReplaceSectionDeep(self):
6649 """Test replacing an entry in two levels of sections"""
6650 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6651 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6652 'section/section/blob', expect_data,
6653 dts='278_replace_section_deep.dts')
6654 self.assertEqual(expect_data, entry_data)
6655
6656 entries = image.GetEntries()
6657 self.assertIn('section', entries)
6658 section = entries['section']
6659
6660 subentries = section.GetEntries()
6661 self.assertIn('section', subentries)
6662 section = subentries['section']
6663
6664 sect_entries = section.GetEntries()
6665 self.assertIn('blob', sect_entries)
6666 entry = sect_entries['blob']
6667 self.assertEqual(len(expect_data), entry.size)
6668
6669 fname = tools.get_output_filename('image-updated.bin')
6670 data = tools.read_file(fname)
6671
6672 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6673 self.assertEqual(expect_data, new_blob_data)
6674
6675 self.assertEqual(U_BOOT_DATA,
6676 data[entry.image_pos + len(expect_data):]
6677 [:len(U_BOOT_DATA)])
6678
6679 def testReplaceFitSibling(self):
6680 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006681 self._SetupSplElf()
Simon Glass7caa3722023-03-02 17:02:44 -07006682 fname = TestFunctional._MakeInputFile('once', b'available once')
6683 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6684 os.remove(fname)
6685
6686 try:
6687 tmpdir, updated_fname = self._SetupImageInTmpdir()
6688
6689 fname = os.path.join(tmpdir, 'update-blob')
6690 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6691 tools.write_file(fname, expected)
6692
6693 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6694 data = tools.read_file(updated_fname)
6695 start = len(U_BOOT_DTB_DATA)
6696 self.assertEqual(expected, data[start:start + len(expected)])
6697 map_fname = os.path.join(tmpdir, 'image-updated.map')
6698 self.assertFalse(os.path.exists(map_fname))
6699 finally:
6700 shutil.rmtree(tmpdir)
6701
Simon Glass953d4172023-03-02 17:02:45 -07006702 def testX509Cert(self):
6703 """Test creating an X509 certificate"""
6704 keyfile = self.TestFile('key.key')
6705 entry_args = {
6706 'keyfile': keyfile,
6707 }
6708 data = self._DoReadFileDtb('279_x509_cert.dts',
6709 entry_args=entry_args)[0]
6710 cert = data[:-4]
6711 self.assertEqual(U_BOOT_DATA, data[-4:])
6712
6713 # TODO: verify the signature
6714
6715 def testX509CertMissing(self):
6716 """Test that binman still produces an image if openssl is missing"""
6717 keyfile = self.TestFile('key.key')
6718 entry_args = {
6719 'keyfile': 'keyfile',
6720 }
6721 with test_util.capture_sys_output() as (_, stderr):
6722 self._DoTestFile('279_x509_cert.dts',
6723 force_missing_bintools='openssl',
6724 entry_args=entry_args)
6725 err = stderr.getvalue()
6726 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6727
Jonas Karlman05b978b2023-02-25 19:01:33 +00006728 def testPackRockchipTpl(self):
6729 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glass176f1f62023-07-24 09:19:58 -06006730 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman05b978b2023-02-25 19:01:33 +00006731 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6732
Jonas Karlman40389c22023-02-25 19:01:35 +00006733 def testMkimageMissingBlobMultiple(self):
6734 """Test missing blob with mkimage entry and multiple-data-files"""
6735 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass176f1f62023-07-24 09:19:58 -06006736 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman40389c22023-02-25 19:01:35 +00006737 err = stderr.getvalue()
6738 self.assertIn("is missing external blobs and is non-functional", err)
6739
6740 with self.assertRaises(ValueError) as e:
Simon Glass176f1f62023-07-24 09:19:58 -06006741 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman40389c22023-02-25 19:01:35 +00006742 self.assertIn("not found in input path", str(e.exception))
6743
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006744 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6745 """Prepare sign environment
6746
6747 Create private and public keys, add pubkey into dtb.
6748
6749 Returns:
6750 Tuple:
6751 FIT container
6752 Image name
6753 Private key
6754 DTB
6755 """
Marek Vasutfadad3a2023-07-18 07:23:58 -06006756 self._SetupSplElf()
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006757 data = self._DoReadFileRealDtb(dts)
6758 updated_fname = tools.get_output_filename('image-updated.bin')
6759 tools.write_file(updated_fname, data)
6760 dtb = tools.get_output_filename('source.dtb')
6761 private_key = tools.get_output_filename('test_key.key')
6762 public_key = tools.get_output_filename('test_key.crt')
6763 fit = tools.get_output_filename('fit.fit')
6764 key_dir = tools.get_output_dir()
6765
6766 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6767 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6768 private_key, '-out', public_key)
6769 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6770 '-n', 'test_key', '-r', 'conf', dtb)
6771
6772 return fit, updated_fname, private_key, dtb
6773
6774 def testSignSimple(self):
6775 """Test that a FIT container can be signed in image"""
6776 is_signed = False
6777 fit, fname, private_key, dtb = self._PrepareSignEnv()
6778
6779 # do sign with private key
6780 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6781 ['fit'])
6782 is_signed = self._CheckSign(fit, dtb)
6783
6784 self.assertEqual(is_signed, True)
6785
6786 def testSignExactFIT(self):
6787 """Test that a FIT container can be signed and replaced in image"""
6788 is_signed = False
6789 fit, fname, private_key, dtb = self._PrepareSignEnv()
6790
6791 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6792 args = []
6793 if self.toolpath:
6794 for path in self.toolpath:
6795 args += ['--toolpath', path]
6796
6797 # do sign with private key
6798 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6799 'sha256,rsa4096', '-f', fit, 'fit')
6800 is_signed = self._CheckSign(fit, dtb)
6801
6802 self.assertEqual(is_signed, True)
6803
6804 def testSignNonFit(self):
6805 """Test a non-FIT entry cannot be signed"""
6806 is_signed = False
6807 fit, fname, private_key, _ = self._PrepareSignEnv(
6808 '281_sign_non_fit.dts')
6809
6810 # do sign with private key
6811 with self.assertRaises(ValueError) as e:
6812 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6813 'sha256,rsa4096', '-f', fit, 'u-boot')
6814 self.assertIn(
6815 "Node '/u-boot': Updating signatures is not supported with this entry type",
6816 str(e.exception))
6817
6818 def testSignMissingMkimage(self):
6819 """Test that FIT signing handles a missing mkimage tool"""
6820 fit, fname, private_key, _ = self._PrepareSignEnv()
6821
6822 # try to sign with a missing mkimage tool
6823 bintool.Bintool.set_missing_list(['mkimage'])
6824 with self.assertRaises(ValueError) as e:
6825 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6826 ['fit'])
6827 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6828
Simon Glass4649bea2023-07-18 07:23:54 -06006829 def testSymbolNoWrite(self):
6830 """Test disabling of symbol writing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006831 self._SetupSplElf()
Simon Glass4649bea2023-07-18 07:23:54 -06006832 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6833 no_write_symbols=True)
6834
6835 def testSymbolNoWriteExpanded(self):
6836 """Test disabling of symbol writing in expanded entries"""
6837 entry_args = {
6838 'spl-dtb': '1',
6839 }
6840 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6841 U_BOOT_SPL_DTB_DATA, 0x38,
6842 entry_args=entry_args, use_expanded=True,
6843 no_write_symbols=True)
6844
Marek Vasutfadad3a2023-07-18 07:23:58 -06006845 def testMkimageSpecial(self):
6846 """Test mkimage ignores special hash-1 node"""
6847 data = self._DoReadFile('283_mkimage_special.dts')
6848
6849 # Just check that the data appears in the file somewhere
6850 self.assertIn(U_BOOT_DATA, data)
6851
Simon Glassb1e40ee2023-07-18 07:23:59 -06006852 def testFitFdtList(self):
6853 """Test an image with an FIT with the fit,fdt-list-val option"""
6854 entry_args = {
6855 'default-dt': 'test-fdt2',
6856 }
6857 data = self._DoReadFileDtb(
6858 '284_fit_fdt_list.dts',
6859 entry_args=entry_args,
6860 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6861 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6862 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6863
Simon Glasse1ad57e2023-07-18 07:24:01 -06006864 def testSplEmptyBss(self):
6865 """Test an expanded SPL with a zero-size BSS"""
6866 # ELF file with a '__bss_size' symbol
6867 self._SetupSplElf(src_fname='bss_data_zero')
6868
6869 entry_args = {
6870 'spl-bss-pad': 'y',
6871 'spl-dtb': 'y',
6872 }
6873 data = self._DoReadFileDtb('285_spl_expand.dts',
6874 use_expanded=True, entry_args=entry_args)[0]
6875
Simon Glassf6abd522023-07-18 07:24:04 -06006876 def testTemplate(self):
6877 """Test using a template"""
6878 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6879 data = self._DoReadFile('286_template.dts')
6880 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6881 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6882 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6883
Simon Glassb2f47a52023-07-22 21:43:52 -06006884 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6885 self.assertTrue(os.path.exists(dtb_fname1))
6886 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6887 dtb.Scan()
6888 node1 = dtb.GetNode('/binman/template')
6889 self.assertTrue(node1)
6890 vga = dtb.GetNode('/binman/first/intel-vga')
6891 self.assertTrue(vga)
6892
Simon Glassaf41b242023-07-22 21:43:56 -06006893 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6894 self.assertTrue(os.path.exists(dtb_fname2))
6895 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6896 dtb2.Scan()
6897 node2 = dtb2.GetNode('/binman/template')
6898 self.assertFalse(node2)
6899
Simon Glass35f72fb2023-07-18 07:24:05 -06006900 def testTemplateBlobMulti(self):
6901 """Test using a template with 'multiple-images' enabled"""
6902 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6903 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6904 retcode = self._DoTestFile('287_template_multi.dts')
6905
6906 self.assertEqual(0, retcode)
6907 image = control.images['image']
6908 image_fname = tools.get_output_filename('my-image.bin')
6909 data = tools.read_file(image_fname)
6910 self.assertEqual(b'blob@@@@other', data)
6911
Simon Glassdb0e3f12023-07-18 07:24:06 -06006912 def testTemplateFit(self):
6913 """Test using a template in a FIT"""
6914 fit_data = self._DoReadFile('288_template_fit.dts')
6915 fname = os.path.join(self._indir, 'fit_data.fit')
6916 tools.write_file(fname, fit_data)
6917 out = tools.run('dumpimage', '-l', fname)
6918
Simon Glass696f2b72023-07-18 07:24:07 -06006919 def testTemplateSection(self):
6920 """Test using a template in a section (not at top level)"""
6921 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6922 data = self._DoReadFile('289_template_section.dts')
6923 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6924 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6925 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6926
Simon Glass23b96e92023-07-18 07:24:08 -06006927 def testMkimageSymbols(self):
6928 """Test using mkimage to build an image with symbols in it"""
6929 self._SetupSplElf('u_boot_binman_syms')
6930 data = self._DoReadFile('290_mkimage_sym.dts')
6931
6932 image = control.images['image']
6933 entries = image.GetEntries()
6934 self.assertIn('u-boot', entries)
6935 u_boot = entries['u-boot']
6936
6937 mkim = entries['mkimage']
6938 mkim_entries = mkim.GetEntries()
6939 self.assertIn('u-boot-spl', mkim_entries)
6940 spl = mkim_entries['u-boot-spl']
6941 self.assertIn('u-boot-spl2', mkim_entries)
6942 spl2 = mkim_entries['u-boot-spl2']
6943
6944 # skip the mkimage header and the area sizes
6945 mk_data = data[mkim.offset + 0x40:]
6946 size, term = struct.unpack('>LL', mk_data[:8])
6947
6948 # There should be only one image, so check that the zero terminator is
6949 # present
6950 self.assertEqual(0, term)
6951
6952 content = mk_data[8:8 + size]
6953
6954 # The image should contain the symbols from u_boot_binman_syms.c
6955 # Note that image_pos is adjusted by the base address of the image,
6956 # which is 0x10 in our test image
6957 spl_data = content[:0x18]
6958 content = content[0x1b:]
6959
6960 # After the header is a table of offsets for each image. There should
6961 # only be one image, then a 0 terminator, so figure out the real start
6962 # of the image data
6963 base = 0x40 + 8
6964
6965 # Check symbols in both u-boot-spl and u-boot-spl2
6966 for i in range(2):
6967 vals = struct.unpack('<LLQLL', spl_data)
6968
6969 # The image should contain the symbols from u_boot_binman_syms.c
6970 # Note that image_pos is adjusted by the base address of the image,
6971 # which is 0x10 in our 'u_boot_binman_syms' test image
6972 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6973 self.assertEqual(base, vals[1])
6974 self.assertEqual(spl2.offset, vals[2])
6975 # figure out the internal positions of its components
6976 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6977
6978 # Check that spl and spl2 are actually at the indicated positions
6979 self.assertEqual(
6980 elf.BINMAN_SYM_MAGIC_VALUE,
6981 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6982 self.assertEqual(
6983 elf.BINMAN_SYM_MAGIC_VALUE,
6984 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6985
6986 self.assertEqual(len(U_BOOT_DATA), vals[4])
6987
6988 # Move to next
6989 spl_data = content[:0x18]
6990
Simon Glassd4d97662023-07-22 21:43:57 -06006991 def testTemplatePhandle(self):
6992 """Test using a template in a node containing a phandle"""
6993 entry_args = {
6994 'atf-bl31-path': 'bl31.elf',
6995 }
Simon Glass93a203d2023-08-03 17:23:58 -06006996 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glassd4d97662023-07-22 21:43:57 -06006997 entry_args=entry_args)
6998 fname = tools.get_output_filename('image.bin')
6999 out = tools.run('dumpimage', '-l', fname)
7000
7001 # We should see the FIT description and one for each of the two images
7002 lines = out.splitlines()
7003 descs = [line.split()[-1] for line in lines if 'escription' in line]
7004 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7005
7006 def testTemplatePhandleDup(self):
7007 """Test using a template in a node containing a phandle"""
7008 entry_args = {
7009 'atf-bl31-path': 'bl31.elf',
7010 }
7011 with self.assertRaises(ValueError) as e:
Simon Glass93a203d2023-08-03 17:23:58 -06007012 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glassd4d97662023-07-22 21:43:57 -06007013 entry_args=entry_args)
7014 self.assertIn(
7015 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7016 str(e.exception))
7017
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307018 def testTIBoardConfig(self):
7019 """Test that a schema validated board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06007020 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307021 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7022
7023 def testTIBoardConfigCombined(self):
7024 """Test that a schema validated combined board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06007025 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307026 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7027 self.assertGreater(data, configlen_noheader)
7028
7029 def testTIBoardConfigNoDataType(self):
7030 """Test that error is thrown when data type is not supported"""
7031 with self.assertRaises(ValueError) as e:
Simon Glassa6b44ac2023-07-24 09:19:59 -06007032 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307033 self.assertIn("Schema validation error", str(e.exception))
Simon Glassefddab62023-01-07 14:07:08 -07007034
Neha Malcom Francis78144822023-07-22 00:14:25 +05307035 def testPackTiSecure(self):
7036 """Test that an image with a TI secured binary can be created"""
7037 keyfile = self.TestFile('key.key')
7038 entry_args = {
7039 'keyfile': keyfile,
7040 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007041 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307042 entry_args=entry_args)[0]
7043 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7044
7045 def testPackTiSecureMissingTool(self):
7046 """Test that an image with a TI secured binary (non-functional) can be created
7047 when openssl is missing"""
7048 keyfile = self.TestFile('key.key')
7049 entry_args = {
7050 'keyfile': keyfile,
7051 }
7052 with test_util.capture_sys_output() as (_, stderr):
Simon Glassa6b44ac2023-07-24 09:19:59 -06007053 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307054 force_missing_bintools='openssl',
7055 entry_args=entry_args)
7056 err = stderr.getvalue()
7057 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7058
7059 def testPackTiSecureROM(self):
7060 """Test that a ROM image with a TI secured binary can be created"""
7061 keyfile = self.TestFile('key.key')
7062 entry_args = {
7063 'keyfile': keyfile,
7064 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007065 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307066 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06007067 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307068 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06007069 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307070 entry_args=entry_args)[0]
7071 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7072 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7073 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7074
7075 def testPackTiSecureROMCombined(self):
7076 """Test that a ROM image with a TI secured binary can be created"""
7077 keyfile = self.TestFile('key.key')
7078 entry_args = {
7079 'keyfile': keyfile,
7080 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007081 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307082 entry_args=entry_args)[0]
7083 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7084
Christian Taedcke289e6002023-07-17 09:05:54 +02007085 def testEncryptedNoAlgo(self):
7086 """Test encrypted node with missing required properties"""
7087 with self.assertRaises(ValueError) as e:
7088 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7089 self.assertIn(
7090 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7091 str(e.exception))
7092
7093 def testEncryptedInvalidIvfile(self):
7094 """Test encrypted node with invalid iv file"""
7095 with self.assertRaises(ValueError) as e:
7096 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7097 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7098 str(e.exception))
7099
7100 def testEncryptedMissingKey(self):
7101 """Test encrypted node with missing key properties"""
7102 with self.assertRaises(ValueError) as e:
7103 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7104 self.assertIn(
7105 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7106 str(e.exception))
7107
7108 def testEncryptedKeySource(self):
7109 """Test encrypted node with key-source property"""
7110 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7111
7112 dtb = fdt.Fdt.FromData(data)
7113 dtb.Scan()
7114
7115 node = dtb.GetNode('/images/u-boot/cipher')
7116 self.assertEqual('algo-name', node.props['algo'].value)
7117 self.assertEqual('key-source-value', node.props['key-source'].value)
7118 self.assertEqual(ENCRYPTED_IV_DATA,
7119 tools.to_bytes(''.join(node.props['iv'].value)))
7120 self.assertNotIn('key', node.props)
7121
7122 def testEncryptedKeyFile(self):
7123 """Test encrypted node with key-filename property"""
7124 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7125
7126 dtb = fdt.Fdt.FromData(data)
7127 dtb.Scan()
7128
7129 node = dtb.GetNode('/images/u-boot/cipher')
7130 self.assertEqual('algo-name', node.props['algo'].value)
7131 self.assertEqual(ENCRYPTED_IV_DATA,
7132 tools.to_bytes(''.join(node.props['iv'].value)))
7133 self.assertEqual(ENCRYPTED_KEY_DATA,
7134 tools.to_bytes(''.join(node.props['key'].value)))
7135 self.assertNotIn('key-source', node.props)
7136
7137
Lukas Funke8c1fbd12023-07-18 13:53:13 +02007138 def testSplPubkeyDtb(self):
7139 """Test u_boot_spl_pubkey_dtb etype"""
7140 data = tools.read_file(self.TestFile("key.pem"))
7141 self._MakeInputFile("key.crt", data)
7142 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7143 image = control.images['image']
7144 entries = image.GetEntries()
7145 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7146 dtb_data = dtb_entry.GetData()
7147 dtb = fdt.Fdt.FromData(dtb_data)
7148 dtb.Scan()
7149
7150 signature_node = dtb.GetNode('/signature')
7151 self.assertIsNotNone(signature_node)
7152 key_node = signature_node.FindNode("key-key")
7153 self.assertIsNotNone(key_node)
7154 self.assertEqual(fdt_util.GetString(key_node, "required"),
7155 "conf")
7156 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7157 "sha384,rsa4096")
7158 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7159 "key")
7160
Lukas Funked8a2d3b2023-08-03 17:22:14 +02007161 def testXilinxBootgenSigning(self):
7162 """Test xilinx-bootgen etype"""
7163 bootgen = bintool.Bintool.create('bootgen')
7164 self._CheckBintool(bootgen)
7165 data = tools.read_file(self.TestFile("key.key"))
7166 self._MakeInputFile("psk.pem", data)
7167 self._MakeInputFile("ssk.pem", data)
7168 self._SetupPmuFwlElf()
7169 self._SetupSplElf()
7170 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7171 image_fname = tools.get_output_filename('image.bin')
7172
7173 # Read partition header table and check if authentication is enabled
7174 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7175 "-read", image_fname, "pht").splitlines()
7176 attributes = {"authentication": None,
7177 "core": None,
7178 "encryption": None}
7179
7180 for l in bootgen_out:
7181 for a in attributes.keys():
7182 if a in l:
7183 m = re.match(fr".*{a} \[([^]]+)\]", l)
7184 attributes[a] = m.group(1)
7185
7186 self.assertTrue(attributes['authentication'] == "rsa")
7187 self.assertTrue(attributes['core'] == "a53-0")
7188 self.assertTrue(attributes['encryption'] == "no")
7189
7190 def testXilinxBootgenSigningEncryption(self):
7191 """Test xilinx-bootgen etype"""
7192 bootgen = bintool.Bintool.create('bootgen')
7193 self._CheckBintool(bootgen)
7194 data = tools.read_file(self.TestFile("key.key"))
7195 self._MakeInputFile("psk.pem", data)
7196 self._MakeInputFile("ssk.pem", data)
7197 self._SetupPmuFwlElf()
7198 self._SetupSplElf()
7199 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7200 image_fname = tools.get_output_filename('image.bin')
7201
7202 # Read boot header in order to verify encryption source and
7203 # encryption parameter
7204 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7205 "-read", image_fname, "bh").splitlines()
7206 attributes = {"auth_only":
7207 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7208 "encryption_keystore":
7209 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7210 "value": None},
7211 }
7212
7213 for l in bootgen_out:
7214 for a in attributes.keys():
7215 if a in l:
7216 m = re.match(attributes[a]['re'], l)
7217 attributes[a] = m.group(1)
7218
7219 # Check if fsbl-attribute is set correctly
7220 self.assertTrue(attributes['auth_only'] == "true")
7221 # Check if key is stored in efuse
7222 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7223
7224 def testXilinxBootgenMissing(self):
7225 """Test that binman still produces an image if bootgen is missing"""
7226 data = tools.read_file(self.TestFile("key.key"))
7227 self._MakeInputFile("psk.pem", data)
7228 self._MakeInputFile("ssk.pem", data)
7229 self._SetupPmuFwlElf()
7230 self._SetupSplElf()
7231 with test_util.capture_sys_output() as (_, stderr):
7232 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7233 force_missing_bintools='bootgen')
7234 err = stderr.getvalue()
7235 self.assertRegex(err,
7236 "Image 'image'.*missing bintools.*: bootgen")
7237
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307238 def _GetCapsuleHeaders(self, data):
7239 """Get the capsule header contents
7240
7241 Args:
7242 data: Capsule file contents
7243
7244 Returns:
7245 Dict:
7246 key: Capsule Header name (str)
7247 value: Header field value (str)
7248 """
7249 capsule_file = os.path.join(self._indir, 'test.capsule')
7250 tools.write_file(capsule_file, data)
7251
7252 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7253 lines = out.splitlines()
7254
7255 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7256 vals = {}
7257 for line in lines:
7258 mat = re_line.match(line)
7259 if mat:
7260 vals[mat.group(1)] = mat.group(2)
7261
7262 return vals
7263
Sughosh Ganub6176112023-08-22 23:09:59 +05307264 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7265 capoemflags=False):
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307266 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7267 fmp_size = "00000010"
7268 fmp_fw_version = "00000002"
7269 capsule_image_index = "00000001"
7270 oemflag = "00018000"
7271 auth_hdr_revision = "00000200"
7272 auth_hdr_cert_type = "00000EF1"
Sughosh Ganub6176112023-08-22 23:09:59 +05307273
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307274 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganub6176112023-08-22 23:09:59 +05307275
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307276 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganub6176112023-08-22 23:09:59 +05307277
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307278 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7279
7280 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7281 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7282 self.assertEqual(capsule_image_index,
7283 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganub6176112023-08-22 23:09:59 +05307284
7285 if capoemflags:
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307286 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7287
7288 if signed_capsule:
7289 self.assertEqual(auth_hdr_revision,
7290 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7291 self.assertEqual(auth_hdr_cert_type,
7292 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7293 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7294 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7295
7296 if version_check:
7297 self.assertEqual(fmp_signature,
7298 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7299 self.assertEqual(fmp_size,
7300 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7301 self.assertEqual(fmp_fw_version,
7302 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7303
7304 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganub6176112023-08-22 23:09:59 +05307305
Sughosh Ganu74aae502023-10-10 14:40:59 +05307306 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7307 if accept_capsule:
7308 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7309 else:
7310 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7311
7312 hdr = self._GetCapsuleHeaders(data)
7313
7314 self.assertEqual(capsule_hdr_guid.upper(),
7315 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7316
7317 if accept_capsule:
7318 capsule_size = "0000002C"
7319 else:
7320 capsule_size = "0000001C"
7321 self.assertEqual(capsule_size,
7322 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7323
7324 if accept_capsule:
7325 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7326
Sughosh Ganub6176112023-08-22 23:09:59 +05307327 def testCapsuleGen(self):
7328 """Test generation of EFI capsule"""
7329 data = self._DoReadFile('311_capsule.dts')
7330
7331 self._CheckCapsule(data)
7332
7333 def testSignedCapsuleGen(self):
7334 """Test generation of EFI capsule"""
7335 data = tools.read_file(self.TestFile("key.key"))
7336 self._MakeInputFile("key.key", data)
7337 data = tools.read_file(self.TestFile("key.pem"))
7338 self._MakeInputFile("key.crt", data)
7339
7340 data = self._DoReadFile('312_capsule_signed.dts')
7341
7342 self._CheckCapsule(data, signed_capsule=True)
7343
7344 def testCapsuleGenVersionSupport(self):
7345 """Test generation of EFI capsule with version support"""
7346 data = self._DoReadFile('313_capsule_version.dts')
7347
7348 self._CheckCapsule(data, version_check=True)
7349
7350 def testCapsuleGenSignedVer(self):
7351 """Test generation of signed EFI capsule with version information"""
7352 data = tools.read_file(self.TestFile("key.key"))
7353 self._MakeInputFile("key.key", data)
7354 data = tools.read_file(self.TestFile("key.pem"))
7355 self._MakeInputFile("key.crt", data)
7356
7357 data = self._DoReadFile('314_capsule_signed_ver.dts')
7358
7359 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7360
7361 def testCapsuleGenCapOemFlags(self):
7362 """Test generation of EFI capsule with OEM Flags set"""
7363 data = self._DoReadFile('315_capsule_oemflags.dts')
7364
7365 self._CheckCapsule(data, capoemflags=True)
7366
7367 def testCapsuleGenKeyMissing(self):
7368 """Test that binman errors out on missing key"""
7369 with self.assertRaises(ValueError) as e:
7370 self._DoReadFile('316_capsule_missing_key.dts')
7371
7372 self.assertIn("Both private key and public key certificate need to be provided",
7373 str(e.exception))
7374
7375 def testCapsuleGenIndexMissing(self):
7376 """Test that binman errors out on missing image index"""
7377 with self.assertRaises(ValueError) as e:
7378 self._DoReadFile('317_capsule_missing_index.dts')
7379
7380 self.assertIn("entry is missing properties: image-index",
7381 str(e.exception))
7382
7383 def testCapsuleGenGuidMissing(self):
7384 """Test that binman errors out on missing image GUID"""
7385 with self.assertRaises(ValueError) as e:
7386 self._DoReadFile('318_capsule_missing_guid.dts')
7387
7388 self.assertIn("entry is missing properties: image-guid",
7389 str(e.exception))
7390
Sughosh Ganu74aae502023-10-10 14:40:59 +05307391 def testCapsuleGenAcceptCapsule(self):
7392 """Test generationg of accept EFI capsule"""
7393 data = self._DoReadFile('319_capsule_accept.dts')
7394
7395 self._CheckEmptyCapsule(data, accept_capsule=True)
7396
7397 def testCapsuleGenRevertCapsule(self):
7398 """Test generationg of revert EFI capsule"""
7399 data = self._DoReadFile('320_capsule_revert.dts')
7400
7401 self._CheckEmptyCapsule(data)
7402
7403 def testCapsuleGenAcceptGuidMissing(self):
7404 """Test that binman errors out on missing image GUID for accept capsule"""
7405 with self.assertRaises(ValueError) as e:
7406 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7407
7408 self.assertIn("Image GUID needed for generating accept capsule",
7409 str(e.exception))
7410
7411 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7412 """Test that capsule-type is specified"""
7413 with self.assertRaises(ValueError) as e:
7414 self._DoReadFile('322_empty_capsule_type_missing.dts')
7415
7416 self.assertIn("entry is missing properties: capsule-type",
7417 str(e.exception))
7418
7419 def testCapsuleGenAcceptOrRevertMissing(self):
7420 """Test that both accept and revert capsule are not specified"""
7421 with self.assertRaises(ValueError) as e:
7422 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7423
Simon Glass9fc60b42017-11-12 21:52:22 -07007424if __name__ == "__main__":
7425 unittest.main()