blob: 5ace2a825dc5753827b29593695b8bd3b0336407 [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'
Simon Glass75989722021-11-23 21:08:59 -070091ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080092OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050093SCP_DATA = b'scp'
Jonas Karlman05b978b2023-02-25 19:01:33 +000094ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glass6cf99532020-09-01 05:13:59 -060095TEST_FDT1_DATA = b'fdt1'
96TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060097ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke289e6002023-07-17 09:05:54 +020098ENCRYPTED_IV_DATA = b'123456'
99ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesb1c50932022-03-28 22:57:04 +0200100PRE_LOAD_MAGIC = b'UBSH'
101PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
102PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530103TI_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 +0530104TI_UNSECURE_DATA = b'unsecuredata'
Simon Glass6cf99532020-09-01 05:13:59 -0600105
106# Subdirectory of the input dir to use to put test FDTs
107TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600108
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600109# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600110EXTRACT_DTB_SIZE = 0x3c9
111
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600112# Properties expected to be in the device tree when update_dtb is used
113BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
114
Simon Glass12bb1a92019-07-20 12:23:51 -0600115# Extra properties expected to be in the device tree when allow-repack is used
116REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
117
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200118# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200119COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700120
Simon Glass2f80c5e2023-01-07 14:07:14 -0700121TEE_ADDR = 0x5678
122
Sughosh Ganub6176112023-08-22 23:09:59 +0530123# Firmware Management Protocol(FMP) GUID
Sughosh Ganu809f28e2023-10-10 14:40:57 +0530124FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganub6176112023-08-22 23:09:59 +0530125# Image GUID specified in the DTS
Sughosh Ganu809f28e2023-10-10 14:40:57 +0530126CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
127# Windows cert GUID
128WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu74aae502023-10-10 14:40:59 +0530129# Empty capsule GUIDs
130EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
131EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganub6176112023-08-22 23:09:59 +0530132
Simon Glass4f443042016-11-25 20:15:52 -0700133class TestFunctional(unittest.TestCase):
134 """Functional tests for binman
135
136 Most of these use a sample .dts file to build an image and then check
137 that it looks correct. The sample files are in the test/ subdirectory
138 and are numbered.
139
140 For each entry type a very small test file is created using fixed
141 string contents. This makes it easy to test that things look right, and
142 debug problems.
143
144 In some cases a 'real' file must be used - these are also supplied in
145 the test/ diurectory.
146 """
147 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600148 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700149 global entry
Simon Glass16287932020-04-17 18:09:03 -0600150 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700151
Simon Glass4f443042016-11-25 20:15:52 -0700152 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600153 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
154 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700155
156 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600157 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700158
159 # Create some test files
160 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
161 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
162 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600163 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700164 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700165 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700166 TestFunctional._MakeInputFile('me.bin', ME_DATA)
167 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600168 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600169
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530170 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600171
Simon Glass5e239182019-08-24 07:22:49 -0600172 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
173 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700174 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600175 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600176 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600177
178 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
179 X86_RESET16_DATA)
180 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
181 X86_RESET16_SPL_DATA)
182 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
183 X86_RESET16_TPL_DATA)
184
Simon Glass4f443042016-11-25 20:15:52 -0700185 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700186 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
187 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600188 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
189 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700190 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
191 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700192 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
193 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700194 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700195 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600196 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600197 TestFunctional._MakeInputDir('devkeys')
198 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600199 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600200 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600201 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600202 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700203
Simon Glass53e22bf2019-08-24 07:22:53 -0600204 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
205 elf_test.BuildElfTestFiles(cls._elf_testdir)
206
Simon Glasse0ff8552016-11-25 20:15:53 -0700207 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600208 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700209 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700210
211 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600212 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700213
Simon Glassb986b3b2019-08-24 07:22:43 -0600214 shutil.copytree(cls.TestFile('files'),
215 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600216
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530217 shutil.copytree(cls.TestFile('yaml'),
218 os.path.join(cls._indir, 'yaml'))
219
Simon Glass83d73c22018-09-14 04:57:26 -0600220 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600221 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600222 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200223 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700224 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800225 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500226 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman05b978b2023-02-25 19:01:33 +0000227 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis78144822023-07-22 00:14:25 +0530228 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganub6176112023-08-22 23:09:59 +0530229 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600230
Simon Glass6cf99532020-09-01 05:13:59 -0600231 # Add a few .dtb files for testing
232 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
233 TEST_FDT1_DATA)
234 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
235 TEST_FDT2_DATA)
236
Simon Glassfb91d562020-09-06 10:35:33 -0600237 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
238
Simon Glass40c8bdd2022-03-05 20:19:12 -0700239 # ELF file with two sections in different parts of memory, used for both
240 # ATF and OP_TEE
241 TestFunctional._MakeInputFile('bl31.elf',
242 tools.read_file(cls.ElfTestFile('elf_sections')))
243 TestFunctional._MakeInputFile('tee.elf',
244 tools.read_file(cls.ElfTestFile('elf_sections')))
245
Simon Glass2f80c5e2023-01-07 14:07:14 -0700246 # Newer OP_TEE file in v1 binary format
247 cls.make_tee_bin('tee.bin')
248
Christian Taedcke289e6002023-07-17 09:05:54 +0200249 # test files for encrypted tests
250 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
251 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
252
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200253 cls.comp_bintools = {}
254 for name in COMP_BINTOOLS:
255 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600256
Simon Glass4f443042016-11-25 20:15:52 -0700257 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600258 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700259 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600260 if cls.preserve_indir:
261 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600262 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600263 if cls._indir:
264 shutil.rmtree(cls._indir)
265 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700266
Simon Glassd5164a72019-07-08 13:18:49 -0600267 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600268 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600269 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600270 """Accept arguments controlling test execution
271
272 Args:
273 preserve_indir: Preserve the shared input directory used by all
274 tests in this class.
275 preserve_outdir: Preserve the output directories used by tests. Each
276 test has its own, so this is normally only useful when running a
277 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600278 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600279 """
280 cls.preserve_indir = preserve_indir
281 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600282 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600283 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600284
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200285 def _CheckBintool(self, bintool):
286 if not bintool.is_present():
287 self.skipTest('%s not available' % bintool.name)
288
Simon Glassac62fba2019-07-08 13:18:53 -0600289 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200290 bintool = self.comp_bintools['lz4']
291 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600292
Simon Glassbf574f12019-07-20 12:24:09 -0600293 def _CleanupOutputDir(self):
294 """Remove the temporary output directory"""
295 if self.preserve_outdirs:
296 print('Preserving output dir: %s' % tools.outdir)
297 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700298 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600299
Simon Glass4f443042016-11-25 20:15:52 -0700300 def setUp(self):
301 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700302 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700303 command.test_result = None
304
305 def tearDown(self):
306 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600307 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700308
Simon Glassf86a7362019-07-20 12:24:10 -0600309 def _SetupImageInTmpdir(self):
310 """Set up the output image in a new temporary directory
311
312 This is used when an image has been generated in the output directory,
313 but we want to run binman again. This will create a new output
314 directory and fail to delete the original one.
315
316 This creates a new temporary directory, copies the image to it (with a
317 new name) and removes the old output directory.
318
319 Returns:
320 Tuple:
321 Temporary directory to use
322 New image filename
323 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700324 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600325 tmpdir = tempfile.mkdtemp(prefix='binman.')
326 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700327 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600328 self._CleanupOutputDir()
329 return tmpdir, updated_fname
330
Simon Glassb8ef5b62018-07-17 13:25:48 -0600331 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600332 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600333 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
334 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
335 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700336 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600337
Simon Glass4f443042016-11-25 20:15:52 -0700338 def _RunBinman(self, *args, **kwargs):
339 """Run binman using the command line
340
341 Args:
342 Arguments to pass, as a list of strings
343 kwargs: Arguments to pass to Command.RunPipe()
344 """
Simon Glassd9800692022-01-29 14:14:05 -0700345 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700346 capture=True, capture_stderr=True, raise_on_error=False)
347 if result.return_code and kwargs.get('raise_on_error', True):
348 raise Exception("Error running '%s': %s" % (' '.join(args),
349 result.stdout + result.stderr))
350 return result
351
Simon Glass53cd5d92019-07-08 14:25:29 -0600352 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700353 """Run binman using directly (in the same process)
354
355 Args:
356 Arguments to pass, as a list of strings
357 Returns:
358 Return value (0 for success)
359 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600360 argv = list(argv)
361 args = cmdline.ParseArgs(argv)
362 args.pager = 'binman-invalid-pager'
363 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700364
365 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600366 # args.verbosity = tout.DEBUG
367 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700368
Simon Glass53af22a2018-07-17 13:25:32 -0600369 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600370 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300371 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100372 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700373 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis15432ea2023-07-22 00:14:44 +0530374 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass4f443042016-11-25 20:15:52 -0700375 """Run binman with a given test file
376
377 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600378 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600379 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600380 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600381 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600382 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600383 entry_args: Dict of entry args to supply to binman
384 key: arg name
385 value: value of that arg
386 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600387 use_real_dtb: True to use the test file as the contents of
388 the u-boot-dtb entry. Normally this is not needed and the
389 test contents (the U_BOOT_DTB_DATA string) can be used.
390 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300391 use_expanded: True to use expanded entries where available, e.g.
392 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600393 verbosity: Verbosity level to use (0-3, None=don't set it)
394 allow_missing: Set the '--allow-missing' flag so that missing
395 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100396 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600397 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600398 threads: Number of threads to use (None for default, 0 for
399 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600400 test_section_timeout: True to force the first time to timeout, as
401 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600402 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700403 force_missing_tools (str): comma-separated list of bintools to
404 regard as missing
Andrew Davis15432ea2023-07-22 00:14:44 +0530405 output_dir: Specific output directory to use for image using -O
Simon Glass7115f002021-11-03 21:09:17 -0600406
407 Returns:
408 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700409 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600410 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700411 if debug:
412 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600413 if verbosity is not None:
414 args.append('-v%d' % verbosity)
415 elif self.verbosity:
416 args.append('-v%d' % self.verbosity)
417 if self.toolpath:
418 for path in self.toolpath:
419 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600420 if threads is not None:
421 args.append('-T%d' % threads)
422 if test_section_timeout:
423 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600424 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600425 if map:
426 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600427 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600428 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600429 if not use_real_dtb:
430 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300431 if not use_expanded:
432 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600433 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600434 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600435 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600436 if allow_missing:
437 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700438 if ignore_missing:
439 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100440 if allow_fake_blobs:
441 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700442 if force_missing_bintools:
443 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600444 if update_fdt_in_elf:
445 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600446 if images:
447 for image in images:
448 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600449 if extra_indirs:
450 for indir in extra_indirs:
451 args += ['-I', indir]
Andrew Davis15432ea2023-07-22 00:14:44 +0530452 if output_dir:
453 args += ['-O', output_dir]
Simon Glass7fe91732017-11-13 18:55:00 -0700454 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700455
456 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700457 """Set up a new test device-tree file
458
459 The given file is compiled and set up as the device tree to be used
460 for ths test.
461
462 Args:
463 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600464 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700465
466 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600467 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700468 """
Simon Glassa004f292019-07-20 12:23:49 -0600469 tmpdir = tempfile.mkdtemp(prefix='binmant.')
470 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600471 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700472 data = fd.read()
473 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600474 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600475 return data
Simon Glass4f443042016-11-25 20:15:52 -0700476
Simon Glass6ad24522022-02-28 07:16:54 -0700477 def _GetDtbContentsForSpls(self, dtb_data, name):
478 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glass6ed45ba2018-09-14 04:57:24 -0600479
480 For testing we don't actually have different versions of the DTB. With
481 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
482 we don't normally have any unwanted nodes.
483
484 We still want the DTBs for SPL and TPL to be different though, since
485 otherwise it is confusing to know which one we are looking at. So add
486 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600487
488 Args:
489 dtb_data: dtb data to modify (this should be a value devicetree)
490 name: Name of a new property to add
491
492 Returns:
493 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600494 """
495 dtb = fdt.Fdt.FromData(dtb_data)
496 dtb.Scan()
497 dtb.GetNode('/binman').AddZeroProp(name)
498 dtb.Sync(auto_resize=True)
499 dtb.Pack()
500 return dtb.GetContents()
501
Simon Glass63aeaeb2021-03-18 20:25:05 +1300502 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
503 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600504 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700505 """Run binman and return the resulting image
506
507 This runs binman with a given test file and then reads the resulting
508 output file. It is a shortcut function since most tests need to do
509 these steps.
510
511 Raises an assertion failure if binman returns a non-zero exit code.
512
513 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600514 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700515 use_real_dtb: True to use the test file as the contents of
516 the u-boot-dtb entry. Normally this is not needed and the
517 test contents (the U_BOOT_DTB_DATA string) can be used.
518 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300519 use_expanded: True to use expanded entries where available, e.g.
520 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600521 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600522 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600523 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600524 entry_args: Dict of entry args to supply to binman
525 key: arg name
526 value: value of that arg
527 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
528 function. If reset_dtbs is True, then the original test dtb
529 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600530 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600531 threads: Number of threads to use (None for default, 0 for
532 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700533
534 Returns:
535 Tuple:
536 Resulting image contents
537 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600538 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600539 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700540 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700541 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700542 # Use the compiled test file as the u-boot-dtb input
543 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700544 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600545
546 # For testing purposes, make a copy of the DT for SPL and TPL. Add
547 # a node indicating which it is, so aid verification.
Simon Glass6ad24522022-02-28 07:16:54 -0700548 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -0600549 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
550 outfile = os.path.join(self._indir, dtb_fname)
551 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass6ad24522022-02-28 07:16:54 -0700552 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700553
554 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600555 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600556 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600557 use_expanded=use_expanded, extra_indirs=extra_indirs,
558 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700559 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700560 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700561
562 # Find the (only) image, read it and return its contents
563 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700564 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600565 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600566 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700567 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600568 with open(map_fname) as fd:
569 map_data = fd.read()
570 else:
571 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600572 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600573 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700574 finally:
575 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600576 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600577 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700578
Simon Glass3c081312019-07-08 14:25:26 -0600579 def _DoReadFileRealDtb(self, fname):
580 """Run binman with a real .dtb file and return the resulting data
581
582 Args:
583 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
584
585 Returns:
586 Resulting image contents
587 """
588 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
589
Simon Glasse0ff8552016-11-25 20:15:53 -0700590 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600591 """Helper function which discards the device-tree binary
592
593 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600594 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600595 use_real_dtb: True to use the test file as the contents of
596 the u-boot-dtb entry. Normally this is not needed and the
597 test contents (the U_BOOT_DTB_DATA string) can be used.
598 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600599
600 Returns:
601 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600602 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700603 return self._DoReadFileDtb(fname, use_real_dtb)[0]
604
Simon Glass4f443042016-11-25 20:15:52 -0700605 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600606 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700607 """Create a new test input file, creating directories as needed
608
609 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600610 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700611 contents: File contents to write in to the file
612 Returns:
613 Full pathname of file created
614 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600615 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700616 dirname = os.path.dirname(pathname)
617 if dirname and not os.path.exists(dirname):
618 os.makedirs(dirname)
619 with open(pathname, 'wb') as fd:
620 fd.write(contents)
621 return pathname
622
623 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600624 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600625 """Create a new test input directory, creating directories as needed
626
627 Args:
628 dirname: Directory name to create
629
630 Returns:
631 Full pathname of directory created
632 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600633 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600634 if not os.path.exists(pathname):
635 os.makedirs(pathname)
636 return pathname
637
638 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600639 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600640 """Set up an ELF file with a '_dt_ucode_base_size' symbol
641
642 Args:
643 Filename of ELF file to use as SPL
644 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600645 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700646 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600647
648 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600649 def _SetupTplElf(cls, src_fname='bss_data'):
650 """Set up an ELF file with a '_dt_ucode_base_size' symbol
651
652 Args:
653 Filename of ELF file to use as TPL
654 """
655 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700656 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600657
658 @classmethod
Simon Glass6ad24522022-02-28 07:16:54 -0700659 def _SetupVplElf(cls, src_fname='bss_data'):
660 """Set up an ELF file with a '_dt_ucode_base_size' symbol
661
662 Args:
663 Filename of ELF file to use as VPL
664 """
665 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
666 tools.read_file(cls.ElfTestFile(src_fname)))
667
668 @classmethod
Lukas Funke8c1fbd12023-07-18 13:53:13 +0200669 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
670 """Set up an ELF file with a '_dt_ucode_base_size' symbol
671
672 Args:
673 Filename of ELF file to use as VPL
674 """
675 TestFunctional._MakeInputFile('pmu-firmware.elf',
676 tools.read_file(cls.ElfTestFile(src_fname)))
677
678 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600679 def _SetupDescriptor(cls):
680 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
681 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
682
683 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600684 def TestFile(cls, fname):
685 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700686
Simon Glass53e22bf2019-08-24 07:22:53 -0600687 @classmethod
688 def ElfTestFile(cls, fname):
689 return os.path.join(cls._elf_testdir, fname)
690
Simon Glass2f80c5e2023-01-07 14:07:14 -0700691 @classmethod
692 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
693 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
694 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
695 dummy, paged_sz) + U_BOOT_DATA
696 data += extra_data
697 TestFunctional._MakeInputFile(fname, data)
698
Simon Glass4f443042016-11-25 20:15:52 -0700699 def AssertInList(self, grep_list, target):
700 """Assert that at least one of a list of things is in a target
701
702 Args:
703 grep_list: List of strings to check
704 target: Target string
705 """
706 for grep in grep_list:
707 if grep in target:
708 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600709 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700710
711 def CheckNoGaps(self, entries):
712 """Check that all entries fit together without gaps
713
714 Args:
715 entries: List of entries to check
716 """
Simon Glass3ab95982018-08-01 15:22:37 -0600717 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700718 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600719 self.assertEqual(offset, entry.offset)
720 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700721
Simon Glasse0ff8552016-11-25 20:15:53 -0700722 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600723 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700724
725 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600726 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700727
728 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600729 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700730 """
731 return struct.unpack('>L', dtb[4:8])[0]
732
Simon Glass086cec92019-07-08 14:25:27 -0600733 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600734 def AddNode(node, path):
735 if node.name != '/':
736 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600737 for prop in node.props.values():
738 if prop.name in prop_names:
739 prop_path = path + ':' + prop.name
740 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
741 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600742 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600743 AddNode(subnode, path)
744
745 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600746 AddNode(dtb.GetRoot(), '')
747 return tree
748
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +0000749 def _CheckSign(self, fit, key):
750 try:
751 tools.run('fit_check_sign', '-k', key, '-f', fit)
752 except:
753 self.fail('Expected signed FIT container')
754 return False
755 return True
756
Simon Glass4f443042016-11-25 20:15:52 -0700757 def testRun(self):
758 """Test a basic run with valid args"""
759 result = self._RunBinman('-h')
760
761 def testFullHelp(self):
762 """Test that the full help is displayed with -H"""
763 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300764 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500765 # Remove possible extraneous strings
766 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
767 gothelp = result.stdout.replace(extra, '')
768 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700769 self.assertEqual(0, len(result.stderr))
770 self.assertEqual(0, result.return_code)
771
772 def testFullHelpInternal(self):
773 """Test that the full help is displayed with -H"""
774 try:
775 command.test_result = command.CommandResult()
776 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300777 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700778 finally:
779 command.test_result = None
780
781 def testHelp(self):
782 """Test that the basic help is displayed with -h"""
783 result = self._RunBinman('-h')
784 self.assertTrue(len(result.stdout) > 200)
785 self.assertEqual(0, len(result.stderr))
786 self.assertEqual(0, result.return_code)
787
Simon Glass4f443042016-11-25 20:15:52 -0700788 def testBoard(self):
789 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600790 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700791 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300792 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700793 self.assertEqual(0, result)
794
795 def testNeedBoard(self):
796 """Test that we get an error when no board ius supplied"""
797 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600798 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700799 self.assertIn("Must provide a board to process (use -b <board>)",
800 str(e.exception))
801
802 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600803 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700804 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600805 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700806 # We get one error from libfdt, and a different one from fdtget.
807 self.AssertInList(["Couldn't open blob from 'missing_file'",
808 'No such file or directory'], str(e.exception))
809
810 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600811 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700812
813 Since this is a source file it should be compiled and the error
814 will come from the device-tree compiler (dtc).
815 """
816 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600817 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700818 self.assertIn("FATAL ERROR: Unable to parse input tree",
819 str(e.exception))
820
821 def testMissingNode(self):
822 """Test that a device tree without a 'binman' node generates an error"""
823 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600824 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700825 self.assertIn("does not have a 'binman' node", str(e.exception))
826
827 def testEmpty(self):
828 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600829 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700830 self.assertEqual(0, len(result.stderr))
831 self.assertEqual(0, result.return_code)
832
833 def testInvalidEntry(self):
834 """Test that an invalid entry is flagged"""
835 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600836 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600837 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700838 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
839 "'/binman/not-a-valid-type'", str(e.exception))
840
841 def testSimple(self):
842 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600843 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700844 self.assertEqual(U_BOOT_DATA, data)
845
Simon Glass7fe91732017-11-13 18:55:00 -0700846 def testSimpleDebug(self):
847 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600848 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700849
Simon Glass4f443042016-11-25 20:15:52 -0700850 def testDual(self):
851 """Test that we can handle creating two images
852
853 This also tests image padding.
854 """
Simon Glass741f2d62018-10-01 12:22:30 -0600855 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700856 self.assertEqual(0, retcode)
857
858 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600859 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700860 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700861 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600862 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700863 data = fd.read()
864 self.assertEqual(U_BOOT_DATA, data)
865
866 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600867 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700868 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700869 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600870 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700871 data = fd.read()
872 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700873 self.assertEqual(tools.get_bytes(0, 3), data[:3])
874 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700875
876 def testBadAlign(self):
877 """Test that an invalid alignment value is detected"""
878 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600879 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700880 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
881 "of two", str(e.exception))
882
883 def testPackSimple(self):
884 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600885 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700886 self.assertEqual(0, retcode)
887 self.assertIn('image', control.images)
888 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600889 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700890 self.assertEqual(5, len(entries))
891
892 # First u-boot
893 self.assertIn('u-boot', entries)
894 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600895 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700896 self.assertEqual(len(U_BOOT_DATA), entry.size)
897
898 # Second u-boot, aligned to 16-byte boundary
899 self.assertIn('u-boot-align', entries)
900 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600901 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700902 self.assertEqual(len(U_BOOT_DATA), entry.size)
903
904 # Third u-boot, size 23 bytes
905 self.assertIn('u-boot-size', entries)
906 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600907 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700908 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
909 self.assertEqual(23, entry.size)
910
911 # Fourth u-boot, placed immediate after the above
912 self.assertIn('u-boot-next', entries)
913 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600914 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700915 self.assertEqual(len(U_BOOT_DATA), entry.size)
916
Simon Glass3ab95982018-08-01 15:22:37 -0600917 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertIn('u-boot-fixed', entries)
919 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600920 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700921 self.assertEqual(len(U_BOOT_DATA), entry.size)
922
Simon Glass8beb11e2019-07-08 14:25:47 -0600923 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700924
925 def testPackExtra(self):
926 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600927 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
928 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700929
Simon Glass4f443042016-11-25 20:15:52 -0700930 self.assertIn('image', control.images)
931 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600932 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600933 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700934
Samuel Hollandb01ae032023-01-21 17:25:16 -0600935 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700936 self.assertIn('u-boot', entries)
937 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600938 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700939 self.assertEqual(3, entry.pad_before)
940 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600941 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700942 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
943 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600944 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700945
946 # Second u-boot has an aligned size, but it has no effect
947 self.assertIn('u-boot-align-size-nop', entries)
948 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600949 self.assertEqual(pos, entry.offset)
950 self.assertEqual(len(U_BOOT_DATA), entry.size)
951 self.assertEqual(U_BOOT_DATA, entry.data)
952 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
953 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700954
955 # Third u-boot has an aligned size too
956 self.assertIn('u-boot-align-size', entries)
957 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600958 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700959 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600960 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700961 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600962 data[pos:pos + entry.size])
963 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700964
965 # Fourth u-boot has an aligned end
966 self.assertIn('u-boot-align-end', entries)
967 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600968 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700969 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600970 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700971 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600972 data[pos:pos + entry.size])
973 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700974
975 # Fifth u-boot immediately afterwards
976 self.assertIn('u-boot-align-both', entries)
977 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600978 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700979 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600980 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700981 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600982 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700983
Samuel Hollandb01ae032023-01-21 17:25:16 -0600984 # Sixth u-boot with both minimum size and aligned size
985 self.assertIn('u-boot-min-size', entries)
986 entry = entries['u-boot-min-size']
987 self.assertEqual(128, entry.offset)
988 self.assertEqual(32, entry.size)
989 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
990 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
991 data[pos:pos + entry.size])
992
Simon Glass4f443042016-11-25 20:15:52 -0700993 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600994 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700995
Simon Glass4eec34c2020-10-26 17:40:10 -0600996 dtb = fdt.Fdt(out_dtb_fname)
997 dtb.Scan()
998 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
999 expected = {
1000 'image-pos': 0,
1001 'offset': 0,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001002 'size': 160,
Simon Glass4eec34c2020-10-26 17:40:10 -06001003
1004 'u-boot:image-pos': 0,
1005 'u-boot:offset': 0,
1006 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1007
1008 'u-boot-align-size-nop:image-pos': 12,
1009 'u-boot-align-size-nop:offset': 12,
1010 'u-boot-align-size-nop:size': 4,
1011
1012 'u-boot-align-size:image-pos': 16,
1013 'u-boot-align-size:offset': 16,
1014 'u-boot-align-size:size': 32,
1015
1016 'u-boot-align-end:image-pos': 48,
1017 'u-boot-align-end:offset': 48,
1018 'u-boot-align-end:size': 16,
1019
1020 'u-boot-align-both:image-pos': 64,
1021 'u-boot-align-both:offset': 64,
1022 'u-boot-align-both:size': 64,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001023
1024 'u-boot-min-size:image-pos': 128,
1025 'u-boot-min-size:offset': 128,
1026 'u-boot-min-size:size': 32,
Simon Glass4eec34c2020-10-26 17:40:10 -06001027 }
1028 self.assertEqual(expected, props)
1029
Simon Glass4f443042016-11-25 20:15:52 -07001030 def testPackAlignPowerOf2(self):
1031 """Test that invalid entry alignment is detected"""
1032 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001033 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001034 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1035 "of two", str(e.exception))
1036
1037 def testPackAlignSizePowerOf2(self):
1038 """Test that invalid entry size alignment is detected"""
1039 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001040 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001041 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1042 "power of two", str(e.exception))
1043
1044 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001045 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -07001046 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001047 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001048 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001049 "align 0x4 (4)", str(e.exception))
1050
1051 def testPackInvalidSizeAlign(self):
1052 """Test that invalid entry size alignment is detected"""
1053 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001054 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001055 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1056 "align-size 0x4 (4)", str(e.exception))
1057
1058 def testPackOverlap(self):
1059 """Test that overlapping regions are detected"""
1060 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001061 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001062 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001063 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1064 str(e.exception))
1065
1066 def testPackEntryOverflow(self):
1067 """Test that entries that overflow their size are detected"""
1068 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001069 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001070 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1071 "but entry size is 0x3 (3)", str(e.exception))
1072
1073 def testPackImageOverflow(self):
1074 """Test that entries which overflow the image size are detected"""
1075 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001076 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001077 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -07001078 "size 0x3 (3)", str(e.exception))
1079
1080 def testPackImageSize(self):
1081 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -06001082 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001083 self.assertEqual(0, retcode)
1084 self.assertIn('image', control.images)
1085 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001086 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001087
1088 def testPackImageSizeAlign(self):
1089 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001090 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001091 self.assertEqual(0, retcode)
1092 self.assertIn('image', control.images)
1093 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001094 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001095
1096 def testPackInvalidImageAlign(self):
1097 """Test that invalid image alignment is detected"""
1098 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001099 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001100 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001101 "align-size 0x8 (8)", str(e.exception))
1102
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001103 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001104 """Test that invalid image alignment is detected"""
1105 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001106 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001107 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001108 "two", str(e.exception))
1109
1110 def testImagePadByte(self):
1111 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001112 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001113 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001114 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001115 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001116
1117 def testImageName(self):
1118 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001119 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001120 self.assertEqual(0, retcode)
1121 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001122 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001123 self.assertTrue(os.path.exists(fname))
1124
1125 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001126 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001127 self.assertTrue(os.path.exists(fname))
1128
1129 def testBlobFilename(self):
1130 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001131 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001132 self.assertEqual(BLOB_DATA, data)
1133
1134 def testPackSorted(self):
1135 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001136 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001137 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001138 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1139 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001140
Simon Glass3ab95982018-08-01 15:22:37 -06001141 def testPackZeroOffset(self):
1142 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001143 self._SetupSplElf()
Simon Glass4f443042016-11-25 20:15:52 -07001144 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001145 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001146 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001147 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1148 str(e.exception))
1149
1150 def testPackUbootDtb(self):
1151 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001152 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001153 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001154
1155 def testPackX86RomNoSize(self):
1156 """Test that the end-at-4gb property requires a size property"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001157 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001158 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001159 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001160 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001161 "using end-at-4gb", str(e.exception))
1162
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301163 def test4gbAndSkipAtStartTogether(self):
1164 """Test that the end-at-4gb and skip-at-size property can't be used
1165 together"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001166 self._SetupSplElf()
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301167 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001168 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001169 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301170 "'skip-at-start'", str(e.exception))
1171
Simon Glasse0ff8552016-11-25 20:15:53 -07001172 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001173 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001174 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001175 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001176 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001177 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1178 "is outside the section '/binman' starting at "
1179 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001180 str(e.exception))
1181
1182 def testPackX86Rom(self):
1183 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001184 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001185 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001186 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1187 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001188
1189 def testPackX86RomMeNoDesc(self):
1190 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001191 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001192 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001193 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001194 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001195 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1196 str(e.exception))
1197 finally:
1198 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001199
1200 def testPackX86RomBadDesc(self):
1201 """Test that the Intel requires a descriptor entry"""
1202 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001203 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001204 self.assertIn("Node '/binman/intel-me': No offset set with "
1205 "offset-unset: should another entry provide this correct "
1206 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001207
1208 def testPackX86RomMe(self):
1209 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001210 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001211 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001212 if data[:0x1000] != expected_desc:
1213 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001214 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1215
1216 def testPackVga(self):
1217 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001218 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001219 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1220
1221 def testPackStart16(self):
1222 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001223 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001224 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1225
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301226 def testPackPowerpcMpc85xxBootpgResetvec(self):
1227 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1228 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001229 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301230 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1231
Simon Glass736bb0a2018-07-06 10:27:17 -06001232 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001233 """Handle running a test for insertion of microcode
1234
1235 Args:
1236 dts_fname: Name of test .dts file
1237 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001238 ucode_second: True if the microsecond entry is second instead of
1239 third
Simon Glassadc57012018-07-06 10:27:16 -06001240
1241 Returns:
1242 Tuple:
1243 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001244 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001245 in the above (two 4-byte words)
1246 """
Simon Glass6b187df2017-11-12 21:52:27 -07001247 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001248
1249 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001250 if ucode_second:
1251 ucode_content = data[len(nodtb_data):]
1252 ucode_pos = len(nodtb_data)
1253 dtb_with_ucode = ucode_content[16:]
1254 fdt_len = self.GetFdtLen(dtb_with_ucode)
1255 else:
1256 dtb_with_ucode = data[len(nodtb_data):]
1257 fdt_len = self.GetFdtLen(dtb_with_ucode)
1258 ucode_content = dtb_with_ucode[fdt_len:]
1259 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001260 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001261 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001262 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001263 dtb = fdt.FdtScan(fname)
1264 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001265 self.assertTrue(ucode)
1266 for node in ucode.subnodes:
1267 self.assertFalse(node.props.get('data'))
1268
Simon Glasse0ff8552016-11-25 20:15:53 -07001269 # Check that the microcode appears immediately after the Fdt
1270 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001271 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001272 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1273 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001274 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001275
1276 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001277 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001278 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1279 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001280 u_boot = data[:len(nodtb_data)]
1281 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001282
1283 def testPackUbootMicrocode(self):
1284 """Test that x86 microcode can be handled correctly
1285
1286 We expect to see the following in the image, in order:
1287 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1288 place
1289 u-boot.dtb with the microcode removed
1290 the microcode
1291 """
Simon Glass741f2d62018-10-01 12:22:30 -06001292 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001293 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001294 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1295 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001296
Simon Glass160a7662017-05-27 07:38:26 -06001297 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001298 """Test that x86 microcode can be handled correctly
1299
1300 We expect to see the following in the image, in order:
1301 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1302 place
1303 u-boot.dtb with the microcode
1304 an empty microcode region
1305 """
1306 # We need the libfdt library to run this test since only that allows
1307 # finding the offset of a property. This is required by
1308 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001309 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001310
1311 second = data[len(U_BOOT_NODTB_DATA):]
1312
1313 fdt_len = self.GetFdtLen(second)
1314 third = second[fdt_len:]
1315 second = second[:fdt_len]
1316
Simon Glass160a7662017-05-27 07:38:26 -06001317 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1318 self.assertIn(ucode_data, second)
1319 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001320
Simon Glass160a7662017-05-27 07:38:26 -06001321 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001322 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001323 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1324 len(ucode_data))
1325 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001326 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1327 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001328
Simon Glass75db0862016-11-25 20:15:55 -07001329 def testPackUbootSingleMicrocode(self):
1330 """Test that x86 microcode can be handled correctly with fdt_normal.
1331 """
Simon Glass160a7662017-05-27 07:38:26 -06001332 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001333
Simon Glassc49deb82016-11-25 20:15:54 -07001334 def testUBootImg(self):
1335 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001336 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001337 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001338
1339 def testNoMicrocode(self):
1340 """Test that a missing microcode region is detected"""
1341 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001342 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001343 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1344 "node found in ", str(e.exception))
1345
1346 def testMicrocodeWithoutNode(self):
1347 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1348 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001349 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001350 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1351 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1352
1353 def testMicrocodeWithoutNode2(self):
1354 """Test that a missing u-boot-ucode node is detected"""
1355 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001356 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001357 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1358 "microcode region u-boot-ucode", str(e.exception))
1359
1360 def testMicrocodeWithoutPtrInElf(self):
1361 """Test that a U-Boot binary without the microcode symbol is detected"""
1362 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001363 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001364 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001365 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001366
1367 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001368 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1370 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1371
1372 finally:
1373 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001374 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001375 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001376
1377 def testMicrocodeNotInImage(self):
1378 """Test that microcode must be placed within the image"""
1379 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001380 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001381 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1382 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001383 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001384
1385 def testWithoutMicrocode(self):
1386 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001387 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001388 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001389 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001390
1391 # Now check the device tree has no microcode
1392 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1393 second = data[len(U_BOOT_NODTB_DATA):]
1394
1395 fdt_len = self.GetFdtLen(second)
1396 self.assertEqual(dtb, second[:fdt_len])
1397
1398 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1399 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001400 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001401
1402 def testUnknownPosSize(self):
1403 """Test that microcode must be placed within the image"""
1404 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001405 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001406 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001407 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001408
1409 def testPackFsp(self):
1410 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001411 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001412 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1413
1414 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001415 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001416 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001417 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001418
1419 def testPackVbt(self):
1420 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001421 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001422 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001423
Simon Glass56509842017-11-12 21:52:25 -07001424 def testSplBssPad(self):
1425 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001426 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001427 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001428 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001429 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001430 data)
Simon Glass56509842017-11-12 21:52:25 -07001431
Simon Glass86af5112018-10-01 21:12:42 -06001432 def testSplBssPadMissing(self):
1433 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001434 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001435 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001436 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001437 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1438 str(e.exception))
1439
Simon Glass87722132017-11-12 21:52:26 -07001440 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001441 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001442 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001443 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1444
Simon Glass736bb0a2018-07-06 10:27:17 -06001445 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1446 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001447
1448 We expect to see the following in the image, in order:
1449 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1450 correct place
1451 u-boot.dtb with the microcode removed
1452 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001453
1454 Args:
1455 dts: Device tree file to use for test
1456 ucode_second: True if the microsecond entry is second instead of
1457 third
Simon Glass6b187df2017-11-12 21:52:27 -07001458 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001459 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001460 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1461 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001462 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1463 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001464
Simon Glass736bb0a2018-07-06 10:27:17 -06001465 def testPackUbootSplMicrocode(self):
1466 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001467 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001468 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001469
1470 def testPackUbootSplMicrocodeReorder(self):
1471 """Test that order doesn't matter for microcode entries
1472
1473 This is the same as testPackUbootSplMicrocode but when we process the
1474 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1475 entry, so we reply on binman to try later.
1476 """
Simon Glass741f2d62018-10-01 12:22:30 -06001477 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001478 ucode_second=True)
1479
Simon Glassca4f4ff2017-11-12 21:52:28 -07001480 def testPackMrc(self):
1481 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001482 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001483 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1484
Simon Glass47419ea2017-11-13 18:54:55 -07001485 def testSplDtb(self):
1486 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001487 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001488 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001489 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1490
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001491 def testSplNoDtb(self):
1492 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001493 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001494 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001495 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1496
Simon Glass3d433382021-03-21 18:24:30 +13001497 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4649bea2023-07-18 07:23:54 -06001498 use_expanded=False, no_write_symbols=False):
Simon Glassf5898822021-03-18 20:24:56 +13001499 """Check the image contains the expected symbol values
1500
1501 Args:
1502 dts: Device tree file to use for test
1503 base_data: Data before and after 'u-boot' section
1504 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001505 entry_args: Dict of entry args to supply to binman
1506 key: arg name
1507 value: value of that arg
1508 use_expanded: True to use expanded entries where available, e.g.
1509 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001510 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001511 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001512 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1513 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001514 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001515 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001516 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001517
Simon Glass11ae93e2018-10-01 21:12:47 -06001518 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001519 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1520 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001521 # The image should contain the symbols from u_boot_binman_syms.c
1522 # Note that image_pos is adjusted by the base address of the image,
1523 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001524 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1525 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001526 0x10 + u_boot_offset, 0x04)
Simon Glass4649bea2023-07-18 07:23:54 -06001527 if no_write_symbols:
1528 expected = (base_data +
1529 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1530 U_BOOT_DATA + base_data)
1531 else:
1532 expected = (sym_values + base_data[24:] +
1533 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1534 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001535 self.assertEqual(expected, data)
1536
Simon Glassf5898822021-03-18 20:24:56 +13001537 def testSymbols(self):
1538 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001539 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001540
1541 def testSymbolsNoDtb(self):
1542 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001543 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001544 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1545 0x38)
1546
Simon Glassdd57c132018-06-01 09:38:11 -06001547 def testPackUnitAddress(self):
1548 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001549 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001550 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1551
Simon Glass18546952018-06-01 09:38:16 -06001552 def testSections(self):
1553 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001554 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001555 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1556 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1557 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001558 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001559
Simon Glass3b0c3822018-06-01 09:38:20 -06001560 def testMap(self):
1561 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001562 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001563 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700156400000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600156500000000 00000000 00000010 section@0
156600000000 00000000 00000004 u-boot
156700000010 00000010 00000010 section@1
156800000010 00000000 00000004 u-boot
156900000020 00000020 00000004 section@2
157000000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001571''', map_data)
1572
Simon Glassc8d48ef2018-06-01 09:38:21 -06001573 def testNamePrefix(self):
1574 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001575 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001576 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700157700000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600157800000000 00000000 00000010 section@0
157900000000 00000000 00000004 ro-u-boot
158000000010 00000010 00000010 section@1
158100000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001582''', map_data)
1583
Simon Glass736bb0a2018-07-06 10:27:17 -06001584 def testUnknownContents(self):
1585 """Test that obtaining the contents works as expected"""
1586 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001587 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001588 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001589 "processing of contents: remaining ["
1590 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001591
Simon Glass5c890232018-07-06 10:27:19 -06001592 def testBadChangeSize(self):
1593 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001594 try:
1595 state.SetAllowEntryExpansion(False)
1596 with self.assertRaises(ValueError) as e:
1597 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001598 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001599 str(e.exception))
1600 finally:
1601 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001602
Simon Glass16b8d6b2018-07-06 10:27:42 -06001603 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001604 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001605 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001606 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001607 dtb = fdt.Fdt(out_dtb_fname)
1608 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001609 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001610 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001611 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001612 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001613 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001614 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001615 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001616 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001617 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001618 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001619 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001620 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001621 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001622
Simon Glass3ab95982018-08-01 15:22:37 -06001623 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001624 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001625 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001626 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001627 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001628 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001629 'size': 40
1630 }, props)
1631
1632 def testUpdateFdtBad(self):
1633 """Test that we detect when ProcessFdt never completes"""
1634 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001635 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001636 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001637 '[<binman.etype._testing.Entry__testing',
1638 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001639
Simon Glass53af22a2018-07-17 13:25:32 -06001640 def testEntryArgs(self):
1641 """Test passing arguments to entries from the command line"""
1642 entry_args = {
1643 'test-str-arg': 'test1',
1644 'test-int-arg': '456',
1645 }
Simon Glass741f2d62018-10-01 12:22:30 -06001646 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001647 self.assertIn('image', control.images)
1648 entry = control.images['image'].GetEntries()['_testing']
1649 self.assertEqual('test0', entry.test_str_fdt)
1650 self.assertEqual('test1', entry.test_str_arg)
1651 self.assertEqual(123, entry.test_int_fdt)
1652 self.assertEqual(456, entry.test_int_arg)
1653
1654 def testEntryArgsMissing(self):
1655 """Test missing arguments and properties"""
1656 entry_args = {
1657 'test-int-arg': '456',
1658 }
Simon Glass741f2d62018-10-01 12:22:30 -06001659 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001660 entry = control.images['image'].GetEntries()['_testing']
1661 self.assertEqual('test0', entry.test_str_fdt)
1662 self.assertEqual(None, entry.test_str_arg)
1663 self.assertEqual(None, entry.test_int_fdt)
1664 self.assertEqual(456, entry.test_int_arg)
1665
1666 def testEntryArgsRequired(self):
1667 """Test missing arguments and properties"""
1668 entry_args = {
1669 'test-int-arg': '456',
1670 }
1671 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001672 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001673 self.assertIn("Node '/binman/_testing': "
1674 'Missing required properties/entry args: test-str-arg, '
1675 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001676 str(e.exception))
1677
1678 def testEntryArgsInvalidFormat(self):
1679 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001680 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1681 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001682 with self.assertRaises(ValueError) as e:
1683 self._DoBinman(*args)
1684 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1685
1686 def testEntryArgsInvalidInteger(self):
1687 """Test that an invalid entry-argument integer is detected"""
1688 entry_args = {
1689 'test-int-arg': 'abc',
1690 }
1691 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001692 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001693 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1694 "'test-int-arg' (value 'abc') to integer",
1695 str(e.exception))
1696
1697 def testEntryArgsInvalidDatatype(self):
1698 """Test that an invalid entry-argument datatype is detected
1699
1700 This test could be written in entry_test.py except that it needs
1701 access to control.entry_args, which seems more than that module should
1702 be able to see.
1703 """
1704 entry_args = {
1705 'test-bad-datatype-arg': '12',
1706 }
1707 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001708 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001709 entry_args=entry_args)
1710 self.assertIn('GetArg() internal error: Unknown data type ',
1711 str(e.exception))
1712
Simon Glassbb748372018-07-17 13:25:33 -06001713 def testText(self):
1714 """Test for a text entry type"""
1715 entry_args = {
1716 'test-id': TEXT_DATA,
1717 'test-id2': TEXT_DATA2,
1718 'test-id3': TEXT_DATA3,
1719 }
Simon Glass741f2d62018-10-01 12:22:30 -06001720 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001721 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001722 expected = (tools.to_bytes(TEXT_DATA) +
1723 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1724 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001725 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001726 self.assertEqual(expected, data)
1727
Simon Glassfd8d1f72018-07-17 13:25:36 -06001728 def testEntryDocs(self):
1729 """Test for creation of entry documentation"""
1730 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001731 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001732 self.assertTrue(len(stdout.getvalue()) > 0)
1733
1734 def testEntryDocsMissing(self):
1735 """Test handling of missing entry documentation"""
1736 with self.assertRaises(ValueError) as e:
1737 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001738 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001739 self.assertIn('Documentation is missing for modules: u_boot',
1740 str(e.exception))
1741
Simon Glass11e36cc2018-07-17 13:25:38 -06001742 def testFmap(self):
1743 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001744 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001745 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001746 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1747 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001748 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001749 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001750 self.assertEqual(1, fhdr.ver_major)
1751 self.assertEqual(0, fhdr.ver_minor)
1752 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001753 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001754 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001755 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001756 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001757 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001758
Simon Glassc7722e82021-04-03 11:05:09 +13001759 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001760 self.assertEqual(b'SECTION0', fentry.name)
1761 self.assertEqual(0, fentry.offset)
1762 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001763 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001764
1765 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001766 self.assertEqual(b'RO_U_BOOT', fentry.name)
1767 self.assertEqual(0, fentry.offset)
1768 self.assertEqual(4, fentry.size)
1769 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001770
Simon Glassc7722e82021-04-03 11:05:09 +13001771 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001772 self.assertEqual(b'SECTION1', fentry.name)
1773 self.assertEqual(16, fentry.offset)
1774 self.assertEqual(16, fentry.size)
1775 self.assertEqual(0, fentry.flags)
1776
1777 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001778 self.assertEqual(b'RW_U_BOOT', fentry.name)
1779 self.assertEqual(16, fentry.offset)
1780 self.assertEqual(4, fentry.size)
1781 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001782
Simon Glassc7722e82021-04-03 11:05:09 +13001783 fentry = next(fiter)
1784 self.assertEqual(b'FMAP', fentry.name)
1785 self.assertEqual(32, fentry.offset)
1786 self.assertEqual(expect_size, fentry.size)
1787 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001788
Simon Glassec127af2018-07-17 13:25:39 -06001789 def testBlobNamedByArg(self):
1790 """Test we can add a blob with the filename coming from an entry arg"""
1791 entry_args = {
1792 'cros-ec-rw-path': 'ecrw.bin',
1793 }
Simon Glass3decfa32020-09-01 05:13:54 -06001794 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001795
Simon Glass3af8e492018-07-17 13:25:40 -06001796 def testFill(self):
1797 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001798 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001799 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001800 self.assertEqual(expected, data)
1801
1802 def testFillNoSize(self):
1803 """Test for an fill entry type with no size"""
1804 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001805 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001806 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001807 str(e.exception))
1808
Simon Glass0ef87aa2018-07-17 13:25:44 -06001809 def _HandleGbbCommand(self, pipe_list):
1810 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001811 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001812 fname = pipe_list[0][-1]
1813 # Append our GBB data to the file, which will happen every time the
1814 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001815 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001816 fd.write(GBB_DATA)
1817 return command.CommandResult()
1818
1819 def testGbb(self):
1820 """Test for the Chromium OS Google Binary Block"""
1821 command.test_result = self._HandleGbbCommand
1822 entry_args = {
1823 'keydir': 'devkeys',
1824 'bmpblk': 'bmpblk.bin',
1825 }
Simon Glass741f2d62018-10-01 12:22:30 -06001826 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001827
1828 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001829 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1830 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001831 self.assertEqual(expected, data)
1832
1833 def testGbbTooSmall(self):
1834 """Test for the Chromium OS Google Binary Block being large enough"""
1835 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001836 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001837 self.assertIn("Node '/binman/gbb': GBB is too small",
1838 str(e.exception))
1839
1840 def testGbbNoSize(self):
1841 """Test for the Chromium OS Google Binary Block having a size"""
1842 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001843 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001844 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1845 str(e.exception))
1846
Simon Glass4f9ee832022-01-09 20:14:09 -07001847 def testGbbMissing(self):
1848 """Test that binman still produces an image if futility is missing"""
1849 entry_args = {
1850 'keydir': 'devkeys',
1851 }
1852 with test_util.capture_sys_output() as (_, stderr):
1853 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1854 entry_args=entry_args)
1855 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001856 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001857
Simon Glass24d0d3c2018-07-17 13:25:47 -06001858 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001859 """Fake calls to the futility utility
1860
1861 The expected pipe is:
1862
1863 [('futility', 'vbutil_firmware', '--vblock',
1864 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1865 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1866 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1867 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1868
1869 This writes to the output file (here, 'vblock.vblock'). If
1870 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1871 of the input data (here, 'input.vblock').
1872 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001873 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001874 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001875 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001876 if self._hash_data:
1877 infile = pipe_list[0][11]
1878 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001879 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001880 m.update(data)
1881 fd.write(m.digest())
1882 else:
1883 fd.write(VBLOCK_DATA)
1884
Simon Glass24d0d3c2018-07-17 13:25:47 -06001885 return command.CommandResult()
1886
1887 def testVblock(self):
1888 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001889 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001890 command.test_result = self._HandleVblockCommand
1891 entry_args = {
1892 'keydir': 'devkeys',
1893 }
Simon Glass741f2d62018-10-01 12:22:30 -06001894 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001895 entry_args=entry_args)
1896 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1897 self.assertEqual(expected, data)
1898
1899 def testVblockNoContent(self):
1900 """Test we detect a vblock which has no content to sign"""
1901 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001902 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001903 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001904 'property', str(e.exception))
1905
1906 def testVblockBadPhandle(self):
1907 """Test that we detect a vblock with an invalid phandle in contents"""
1908 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001909 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001910 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1911 '1000', str(e.exception))
1912
1913 def testVblockBadEntry(self):
1914 """Test that we detect an entry that points to a non-entry"""
1915 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001916 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001917 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1918 "'other'", str(e.exception))
1919
Simon Glass5af9ebc2021-01-06 21:35:17 -07001920 def testVblockContent(self):
1921 """Test that the vblock signs the right data"""
1922 self._hash_data = True
1923 command.test_result = self._HandleVblockCommand
1924 entry_args = {
1925 'keydir': 'devkeys',
1926 }
1927 data = self._DoReadFileDtb(
1928 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1929 entry_args=entry_args)[0]
1930 hashlen = 32 # SHA256 hash is 32 bytes
1931 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1932 hashval = data[-hashlen:]
1933 dtb = data[len(U_BOOT_DATA):-hashlen]
1934
1935 expected_data = U_BOOT_DATA + dtb
1936
1937 # The hashval should be a hash of the dtb
1938 m = hashlib.sha256()
1939 m.update(expected_data)
1940 expected_hashval = m.digest()
1941 self.assertEqual(expected_hashval, hashval)
1942
Simon Glass4f9ee832022-01-09 20:14:09 -07001943 def testVblockMissing(self):
1944 """Test that binman still produces an image if futility is missing"""
1945 entry_args = {
1946 'keydir': 'devkeys',
1947 }
1948 with test_util.capture_sys_output() as (_, stderr):
1949 self._DoTestFile('074_vblock.dts',
1950 force_missing_bintools='futility',
1951 entry_args=entry_args)
1952 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001953 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001954
Simon Glassb8ef5b62018-07-17 13:25:48 -06001955 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001956 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001957 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001958 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001959 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001960 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1961
Simon Glass15a587c2018-07-17 13:25:51 -06001962 def testUsesPos(self):
1963 """Test that the 'pos' property cannot be used anymore"""
1964 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001965 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001966 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1967 "'pos'", str(e.exception))
1968
Simon Glassd178eab2018-09-14 04:57:08 -06001969 def testFillZero(self):
1970 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001971 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001972 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001973
Simon Glass0b489362018-09-14 04:57:09 -06001974 def testTextMissing(self):
1975 """Test for a text entry type where there is no text"""
1976 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001977 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001978 self.assertIn("Node '/binman/text': No value provided for text label "
1979 "'test-id'", str(e.exception))
1980
Simon Glass35b384c2018-09-14 04:57:10 -06001981 def testPackStart16Tpl(self):
1982 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001983 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001984 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1985
Simon Glass0bfa7b02018-09-14 04:57:12 -06001986 def testSelectImage(self):
1987 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001988 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001989
Simon Glasseb833d82019-04-25 21:58:34 -06001990 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001991 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001992 with test_util.capture_sys_output() as (stdout, stderr):
1993 retcode = self._DoTestFile('006_dual_image.dts',
1994 verbosity=verbosity,
1995 images=['image2'])
1996 self.assertEqual(0, retcode)
1997 if verbosity:
1998 self.assertIn(expected, stdout.getvalue())
1999 else:
2000 self.assertNotIn(expected, stdout.getvalue())
2001
Simon Glassc1aa66e2022-01-29 14:14:04 -07002002 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2003 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06002004 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06002005
Simon Glass6ed45ba2018-09-14 04:57:24 -06002006 def testUpdateFdtAll(self):
2007 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06002008 self._SetupSplElf()
2009 self._SetupTplElf()
Simon Glass3c081312019-07-08 14:25:26 -06002010 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06002011
2012 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06002013 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002014 'image-pos': 0,
2015 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002016 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002017 'section:image-pos': 0,
2018 'section:size': 565,
2019 'section/u-boot-dtb:offset': 0,
2020 'section/u-boot-dtb:image-pos': 0,
2021 'section/u-boot-dtb:size': 565,
2022 'u-boot-spl-dtb:offset': 565,
2023 'u-boot-spl-dtb:image-pos': 565,
2024 'u-boot-spl-dtb:size': 585,
2025 'u-boot-tpl-dtb:offset': 1150,
2026 'u-boot-tpl-dtb:image-pos': 1150,
2027 'u-boot-tpl-dtb:size': 585,
2028 'u-boot-vpl-dtb:image-pos': 1735,
2029 'u-boot-vpl-dtb:offset': 1735,
2030 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002031 }
2032
2033 # We expect three device-tree files in the output, one after the other.
2034 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2035 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2036 # main U-Boot tree. All three should have the same postions and offset.
2037 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07002038 self.maxDiff = None
2039 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002040 dtb = fdt.Fdt.FromData(data[start:])
2041 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06002042 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07002043 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06002044 expected = dict(base_expected)
2045 if item:
2046 expected[item] = 0
2047 self.assertEqual(expected, props)
2048 start += dtb._fdt_obj.totalsize()
2049
2050 def testUpdateFdtOutput(self):
2051 """Test that output DTB files are updated"""
2052 try:
Simon Glass741f2d62018-10-01 12:22:30 -06002053 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06002054 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2055
2056 # Unfortunately, compiling a source file always results in a file
2057 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002058 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002059 # binman as a file called u-boot.dtb. To fix this, copy the file
2060 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002061 start = 0
2062 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002063 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002064 dtb = fdt.Fdt.FromData(data[start:])
2065 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002066 pathname = tools.get_output_filename(os.path.split(fname)[1])
2067 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002068 name = os.path.split(fname)[0]
2069
2070 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002071 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002072 else:
2073 orig_indata = dtb_data
2074 self.assertNotEqual(outdata, orig_indata,
2075 "Expected output file '%s' be updated" % pathname)
2076 self.assertEqual(outdata, data[start:start + size],
2077 "Expected output file '%s' to match output image" %
2078 pathname)
2079 start += size
2080 finally:
2081 self._ResetDtbs()
2082
Simon Glass83d73c22018-09-14 04:57:26 -06002083 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002084 bintool = self.comp_bintools['lz4']
2085 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002086
2087 def testCompress(self):
2088 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002089 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002090 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002091 use_real_dtb=True, update_dtb=True)
2092 dtb = fdt.Fdt(out_dtb_fname)
2093 dtb.Scan()
2094 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2095 orig = self._decompress(data)
2096 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002097
2098 # Do a sanity check on various fields
2099 image = control.images['image']
2100 entries = image.GetEntries()
2101 self.assertEqual(1, len(entries))
2102
2103 entry = entries['blob']
2104 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2105 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2106 orig = self._decompress(entry.data)
2107 self.assertEqual(orig, entry.uncomp_data)
2108
Simon Glass63e7ba62020-10-26 17:40:16 -06002109 self.assertEqual(image.data, entry.data)
2110
Simon Glass83d73c22018-09-14 04:57:26 -06002111 expected = {
2112 'blob:uncomp-size': len(COMPRESS_DATA),
2113 'blob:size': len(data),
2114 'size': len(data),
2115 }
2116 self.assertEqual(expected, props)
2117
Simon Glass0a98b282018-09-14 04:57:28 -06002118 def testFiles(self):
2119 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002120 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002121 self.assertEqual(FILES_DATA, data)
2122
2123 def testFilesCompress(self):
2124 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002125 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002126 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002127
2128 image = control.images['image']
2129 entries = image.GetEntries()
2130 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002131 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002132
Simon Glassc6c10e72019-05-17 22:00:46 -06002133 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002134 for i in range(1, 3):
2135 key = '%d.dat' % i
2136 start = entries[key].image_pos
2137 len = entries[key].size
2138 chunk = data[start:start + len]
2139 orig += self._decompress(chunk)
2140
2141 self.assertEqual(FILES_DATA, orig)
2142
2143 def testFilesMissing(self):
2144 """Test missing files"""
2145 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002146 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002147 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2148 'no files', str(e.exception))
2149
2150 def testFilesNoPattern(self):
2151 """Test missing files"""
2152 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002153 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002154 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2155 str(e.exception))
2156
Simon Glass80a66ae2022-03-05 20:18:59 -07002157 def testExtendSize(self):
2158 """Test an extending entry"""
2159 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002160 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002161 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2162 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2163 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2164 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002165 self.assertEqual(expect, data)
2166 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700216700000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600216800000000 00000000 00000008 fill
216900000008 00000008 00000004 u-boot
21700000000c 0000000c 00000004 section
21710000000c 00000000 00000003 intel-mrc
217200000010 00000010 00000004 u-boot2
217300000014 00000014 0000000c section2
217400000014 00000000 00000008 fill
21750000001c 00000008 00000004 u-boot
217600000020 00000020 00000008 fill2
2177''', map_data)
2178
Simon Glass80a66ae2022-03-05 20:18:59 -07002179 def testExtendSizeBad(self):
2180 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002181 with test_util.capture_sys_output() as (stdout, stderr):
2182 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002183 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002184 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2185 'expanding entry', str(e.exception))
2186
Simon Glasse0e5df92018-09-14 04:57:31 -06002187 def testHash(self):
2188 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002189 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002190 use_real_dtb=True, update_dtb=True)
2191 dtb = fdt.Fdt(out_dtb_fname)
2192 dtb.Scan()
2193 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2194 m = hashlib.sha256()
2195 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002196 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002197
2198 def testHashNoAlgo(self):
2199 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002200 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002201 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2202 'hash node', str(e.exception))
2203
2204 def testHashBadAlgo(self):
2205 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002206 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002207 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002208 str(e.exception))
2209
2210 def testHashSection(self):
2211 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002212 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002213 use_real_dtb=True, update_dtb=True)
2214 dtb = fdt.Fdt(out_dtb_fname)
2215 dtb.Scan()
2216 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2217 m = hashlib.sha256()
2218 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002219 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002220 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002221
Simon Glassf0253632018-09-14 04:57:32 -06002222 def testPackUBootTplMicrocode(self):
2223 """Test that x86 microcode can be handled correctly in TPL
2224
2225 We expect to see the following in the image, in order:
2226 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2227 place
2228 u-boot-tpl.dtb with the microcode removed
2229 the microcode
2230 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002231 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002232 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002233 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002234 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2235 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002236
Simon Glassf8f8df62018-09-14 04:57:34 -06002237 def testFmapX86(self):
2238 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002239 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002240 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002241 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002242 self.assertEqual(expected, data[:32])
2243 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2244
2245 self.assertEqual(0x100, fhdr.image_size)
2246
2247 self.assertEqual(0, fentries[0].offset)
2248 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002249 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002250
2251 self.assertEqual(4, fentries[1].offset)
2252 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002253 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002254
2255 self.assertEqual(32, fentries[2].offset)
2256 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2257 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002258 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002259
2260 def testFmapX86Section(self):
2261 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002262 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002263 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002264 self.assertEqual(expected, data[:32])
2265 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2266
Simon Glass17365752021-04-03 11:05:10 +13002267 self.assertEqual(0x180, fhdr.image_size)
2268 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002269 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002270
Simon Glassc7722e82021-04-03 11:05:09 +13002271 fentry = next(fiter)
2272 self.assertEqual(b'U_BOOT', fentry.name)
2273 self.assertEqual(0, fentry.offset)
2274 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002275
Simon Glassc7722e82021-04-03 11:05:09 +13002276 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002277 self.assertEqual(b'SECTION', fentry.name)
2278 self.assertEqual(4, fentry.offset)
2279 self.assertEqual(0x20 + expect_size, fentry.size)
2280
2281 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002282 self.assertEqual(b'INTEL_MRC', fentry.name)
2283 self.assertEqual(4, fentry.offset)
2284 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002285
Simon Glassc7722e82021-04-03 11:05:09 +13002286 fentry = next(fiter)
2287 self.assertEqual(b'FMAP', fentry.name)
2288 self.assertEqual(36, fentry.offset)
2289 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002290
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002291 def testElf(self):
2292 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002293 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002294 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002295 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002296 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002297 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002298
Simon Glass093d1682019-07-08 13:18:25 -06002299 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002300 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002301 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002302 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002303 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002304 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002305
Simon Glass163ed6c2018-09-14 04:57:36 -06002306 def testPackOverlapMap(self):
2307 """Test that overlapping regions are detected"""
2308 with test_util.capture_sys_output() as (stdout, stderr):
2309 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002310 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002311 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002312 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2313 stdout.getvalue())
2314
2315 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002316 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002317 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002318 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002319 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002320<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002321<none> 00000000 00000004 u-boot
2322<none> 00000003 00000004 u-boot-align
2323''', map_data)
2324
Simon Glass093d1682019-07-08 13:18:25 -06002325 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002326 """Test that an image with an Intel Reference code binary works"""
2327 data = self._DoReadFile('100_intel_refcode.dts')
2328 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2329
Simon Glass9481c802019-04-25 21:58:39 -06002330 def testSectionOffset(self):
2331 """Tests use of a section with an offset"""
2332 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2333 map=True)
2334 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700233500000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600233600000004 00000004 00000010 section@0
233700000004 00000000 00000004 u-boot
233800000018 00000018 00000010 section@1
233900000018 00000000 00000004 u-boot
23400000002c 0000002c 00000004 section@2
23410000002c 00000000 00000004 u-boot
2342''', map_data)
2343 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002344 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2345 tools.get_bytes(0x21, 12) +
2346 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2347 tools.get_bytes(0x61, 12) +
2348 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2349 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002350
Simon Glassac62fba2019-07-08 13:18:53 -06002351 def testCbfsRaw(self):
2352 """Test base handling of a Coreboot Filesystem (CBFS)
2353
2354 The exact contents of the CBFS is verified by similar tests in
2355 cbfs_util_test.py. The tests here merely check that the files added to
2356 the CBFS can be found in the final image.
2357 """
2358 data = self._DoReadFile('102_cbfs_raw.dts')
2359 size = 0xb0
2360
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2363
2364 self.assertIn('u-boot-dtb', cbfs.files)
2365 cfile = cbfs.files['u-boot-dtb']
2366 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2367
2368 def testCbfsArch(self):
2369 """Test on non-x86 architecture"""
2370 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2371 size = 0x100
2372
2373 cbfs = cbfs_util.CbfsReader(data)
2374 self.assertEqual(size, cbfs.rom_size)
2375
2376 self.assertIn('u-boot-dtb', cbfs.files)
2377 cfile = cbfs.files['u-boot-dtb']
2378 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2379
2380 def testCbfsStage(self):
2381 """Tests handling of a Coreboot Filesystem (CBFS)"""
2382 if not elf.ELF_TOOLS:
2383 self.skipTest('Python elftools not available')
2384 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2385 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2386 size = 0xb0
2387
2388 data = self._DoReadFile('104_cbfs_stage.dts')
2389 cbfs = cbfs_util.CbfsReader(data)
2390 self.assertEqual(size, cbfs.rom_size)
2391
2392 self.assertIn('u-boot', cbfs.files)
2393 cfile = cbfs.files['u-boot']
2394 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2395
2396 def testCbfsRawCompress(self):
2397 """Test handling of compressing raw files"""
2398 self._CheckLz4()
2399 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2400 size = 0x140
2401
2402 cbfs = cbfs_util.CbfsReader(data)
2403 self.assertIn('u-boot', cbfs.files)
2404 cfile = cbfs.files['u-boot']
2405 self.assertEqual(COMPRESS_DATA, cfile.data)
2406
2407 def testCbfsBadArch(self):
2408 """Test handling of a bad architecture"""
2409 with self.assertRaises(ValueError) as e:
2410 self._DoReadFile('106_cbfs_bad_arch.dts')
2411 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2412
2413 def testCbfsNoSize(self):
2414 """Test handling of a missing size property"""
2415 with self.assertRaises(ValueError) as e:
2416 self._DoReadFile('107_cbfs_no_size.dts')
2417 self.assertIn('entry must have a size property', str(e.exception))
2418
Simon Glasse2f04742021-11-23 11:03:54 -07002419 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002420 """Test handling of a CBFS entry which does not provide contentsy"""
2421 with self.assertRaises(ValueError) as e:
2422 self._DoReadFile('108_cbfs_no_contents.dts')
2423 self.assertIn('Could not complete processing of contents',
2424 str(e.exception))
2425
2426 def testCbfsBadCompress(self):
2427 """Test handling of a bad architecture"""
2428 with self.assertRaises(ValueError) as e:
2429 self._DoReadFile('109_cbfs_bad_compress.dts')
2430 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2431 str(e.exception))
2432
2433 def testCbfsNamedEntries(self):
2434 """Test handling of named entries"""
2435 data = self._DoReadFile('110_cbfs_name.dts')
2436
2437 cbfs = cbfs_util.CbfsReader(data)
2438 self.assertIn('FRED', cbfs.files)
2439 cfile1 = cbfs.files['FRED']
2440 self.assertEqual(U_BOOT_DATA, cfile1.data)
2441
2442 self.assertIn('hello', cbfs.files)
2443 cfile2 = cbfs.files['hello']
2444 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2445
Simon Glassc5ac1382019-07-08 13:18:54 -06002446 def _SetupIfwi(self, fname):
2447 """Set up to run an IFWI test
2448
2449 Args:
2450 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2451 """
2452 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002453 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002454
2455 # Intel Integrated Firmware Image (IFWI) file
2456 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2457 data = fd.read()
2458 TestFunctional._MakeInputFile(fname,data)
2459
2460 def _CheckIfwi(self, data):
2461 """Check that an image with an IFWI contains the correct output
2462
2463 Args:
2464 data: Conents of output file
2465 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002466 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002467 if data[:0x1000] != expected_desc:
2468 self.fail('Expected descriptor binary at start of image')
2469
2470 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002471 image_fname = tools.get_output_filename('image.bin')
2472 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002473 ifwitool = bintool.Bintool.create('ifwitool')
2474 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002475
Simon Glassc1aa66e2022-01-29 14:14:04 -07002476 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002477 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002478
2479 def testPackX86RomIfwi(self):
2480 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2481 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002482 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002483 self._CheckIfwi(data)
2484
2485 def testPackX86RomIfwiNoDesc(self):
2486 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2487 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002488 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002489 self._CheckIfwi(data)
2490
2491 def testPackX86RomIfwiNoData(self):
2492 """Test that an x86 ROM with IFWI handles missing data"""
2493 self._SetupIfwi('ifwi.bin')
2494 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002495 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002496 self.assertIn('Could not complete processing of contents',
2497 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002498
Simon Glass4f9ee832022-01-09 20:14:09 -07002499 def testIfwiMissing(self):
2500 """Test that binman still produces an image if ifwitool is missing"""
2501 self._SetupIfwi('fitimage.bin')
2502 with test_util.capture_sys_output() as (_, stderr):
2503 self._DoTestFile('111_x86_rom_ifwi.dts',
2504 force_missing_bintools='ifwitool')
2505 err = stderr.getvalue()
2506 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002507 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002508
Simon Glasse073d4e2019-07-08 13:18:56 -06002509 def testCbfsOffset(self):
2510 """Test a CBFS with files at particular offsets
2511
2512 Like all CFBS tests, this is just checking the logic that calls
2513 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2514 """
2515 data = self._DoReadFile('114_cbfs_offset.dts')
2516 size = 0x200
2517
2518 cbfs = cbfs_util.CbfsReader(data)
2519 self.assertEqual(size, cbfs.rom_size)
2520
2521 self.assertIn('u-boot', cbfs.files)
2522 cfile = cbfs.files['u-boot']
2523 self.assertEqual(U_BOOT_DATA, cfile.data)
2524 self.assertEqual(0x40, cfile.cbfs_offset)
2525
2526 self.assertIn('u-boot-dtb', cbfs.files)
2527 cfile2 = cbfs.files['u-boot-dtb']
2528 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2529 self.assertEqual(0x140, cfile2.cbfs_offset)
2530
Simon Glass086cec92019-07-08 14:25:27 -06002531 def testFdtmap(self):
2532 """Test an FDT map can be inserted in the image"""
2533 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2534 fdtmap_data = data[len(U_BOOT_DATA):]
2535 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002536 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002537 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002538
2539 fdt_data = fdtmap_data[16:]
2540 dtb = fdt.Fdt.FromData(fdt_data)
2541 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002542 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002543 self.assertEqual({
2544 'image-pos': 0,
2545 'offset': 0,
2546 'u-boot:offset': 0,
2547 'u-boot:size': len(U_BOOT_DATA),
2548 'u-boot:image-pos': 0,
2549 'fdtmap:image-pos': 4,
2550 'fdtmap:offset': 4,
2551 'fdtmap:size': len(fdtmap_data),
2552 'size': len(data),
2553 }, props)
2554
2555 def testFdtmapNoMatch(self):
2556 """Check handling of an FDT map when the section cannot be found"""
2557 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2558
2559 # Mangle the section name, which should cause a mismatch between the
2560 # correct FDT path and the one expected by the section
2561 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002562 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002563 entries = image.GetEntries()
2564 fdtmap = entries['fdtmap']
2565 with self.assertRaises(ValueError) as e:
2566 fdtmap._GetFdtmap()
2567 self.assertIn("Cannot locate node for path '/binman-suffix'",
2568 str(e.exception))
2569
Simon Glasscf228942019-07-08 14:25:28 -06002570 def testFdtmapHeader(self):
2571 """Test an FDT map and image header can be inserted in the image"""
2572 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2573 fdtmap_pos = len(U_BOOT_DATA)
2574 fdtmap_data = data[fdtmap_pos:]
2575 fdt_data = fdtmap_data[16:]
2576 dtb = fdt.Fdt.FromData(fdt_data)
2577 fdt_size = dtb.GetFdtObj().totalsize()
2578 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002579 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002580 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2581 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2582
2583 def testFdtmapHeaderStart(self):
2584 """Test an image header can be inserted at the image start"""
2585 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2586 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2587 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002588 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002589 offset = struct.unpack('<I', hdr_data[4:])[0]
2590 self.assertEqual(fdtmap_pos, offset)
2591
2592 def testFdtmapHeaderPos(self):
2593 """Test an image header can be inserted at a chosen position"""
2594 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2595 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2596 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002597 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002598 offset = struct.unpack('<I', hdr_data[4:])[0]
2599 self.assertEqual(fdtmap_pos, offset)
2600
2601 def testHeaderMissingFdtmap(self):
2602 """Test an image header requires an fdtmap"""
2603 with self.assertRaises(ValueError) as e:
2604 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2605 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2606 str(e.exception))
2607
2608 def testHeaderNoLocation(self):
2609 """Test an image header with a no specified location is detected"""
2610 with self.assertRaises(ValueError) as e:
2611 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2612 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2613 str(e.exception))
2614
Simon Glassc52c9e72019-07-08 14:25:37 -06002615 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002616 """Test extending an entry after it is packed"""
2617 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002618 self.assertEqual(b'aaa', data[:3])
2619 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2620 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002621
Simon Glass80a66ae2022-03-05 20:18:59 -07002622 def testEntryExtendBad(self):
2623 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002624 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002625 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002626 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002627 str(e.exception))
2628
Simon Glass80a66ae2022-03-05 20:18:59 -07002629 def testEntryExtendSection(self):
2630 """Test extending an entry within a section after it is packed"""
2631 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002632 self.assertEqual(b'aaa', data[:3])
2633 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2634 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002635
Simon Glass6c223fd2019-07-08 14:25:38 -06002636 def testCompressDtb(self):
2637 """Test that compress of device-tree files is supported"""
2638 self._CheckLz4()
2639 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2640 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2641 comp_data = data[len(U_BOOT_DATA):]
2642 orig = self._decompress(comp_data)
2643 dtb = fdt.Fdt.FromData(orig)
2644 dtb.Scan()
2645 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2646 expected = {
2647 'u-boot:size': len(U_BOOT_DATA),
2648 'u-boot-dtb:uncomp-size': len(orig),
2649 'u-boot-dtb:size': len(comp_data),
2650 'size': len(data),
2651 }
2652 self.assertEqual(expected, props)
2653
Simon Glass69f7cb32019-07-08 14:25:41 -06002654 def testCbfsUpdateFdt(self):
2655 """Test that we can update the device tree with CBFS offset/size info"""
2656 self._CheckLz4()
2657 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2658 update_dtb=True)
2659 dtb = fdt.Fdt(out_dtb_fname)
2660 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002661 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002662 del props['cbfs/u-boot:size']
2663 self.assertEqual({
2664 'offset': 0,
2665 'size': len(data),
2666 'image-pos': 0,
2667 'cbfs:offset': 0,
2668 'cbfs:size': len(data),
2669 'cbfs:image-pos': 0,
Simon Glassab326012023-10-14 14:40:28 -06002670 'cbfs/u-boot:offset': 0x30,
Simon Glass69f7cb32019-07-08 14:25:41 -06002671 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassab326012023-10-14 14:40:28 -06002672 'cbfs/u-boot:image-pos': 0x30,
2673 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass69f7cb32019-07-08 14:25:41 -06002674 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassab326012023-10-14 14:40:28 -06002675 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass69f7cb32019-07-08 14:25:41 -06002676 }, props)
2677
Simon Glass8a1ad062019-07-08 14:25:42 -06002678 def testCbfsBadType(self):
2679 """Test an image header with a no specified location is detected"""
2680 with self.assertRaises(ValueError) as e:
2681 self._DoReadFile('126_cbfs_bad_type.dts')
2682 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2683
Simon Glass41b8ba02019-07-08 14:25:43 -06002684 def testList(self):
2685 """Test listing the files in an image"""
2686 self._CheckLz4()
2687 data = self._DoReadFile('127_list.dts')
2688 image = control.images['image']
2689 entries = image.BuildEntryList()
2690 self.assertEqual(7, len(entries))
2691
2692 ent = entries[0]
2693 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002694 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002695 self.assertEqual('section', ent.etype)
2696 self.assertEqual(len(data), ent.size)
2697 self.assertEqual(0, ent.image_pos)
2698 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002699 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002700
2701 ent = entries[1]
2702 self.assertEqual(1, ent.indent)
2703 self.assertEqual('u-boot', ent.name)
2704 self.assertEqual('u-boot', ent.etype)
2705 self.assertEqual(len(U_BOOT_DATA), ent.size)
2706 self.assertEqual(0, ent.image_pos)
2707 self.assertEqual(None, ent.uncomp_size)
2708 self.assertEqual(0, ent.offset)
2709
2710 ent = entries[2]
2711 self.assertEqual(1, ent.indent)
2712 self.assertEqual('section', ent.name)
2713 self.assertEqual('section', ent.etype)
2714 section_size = ent.size
2715 self.assertEqual(0x100, ent.image_pos)
2716 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002717 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002718
2719 ent = entries[3]
2720 self.assertEqual(2, ent.indent)
2721 self.assertEqual('cbfs', ent.name)
2722 self.assertEqual('cbfs', ent.etype)
2723 self.assertEqual(0x400, ent.size)
2724 self.assertEqual(0x100, ent.image_pos)
2725 self.assertEqual(None, ent.uncomp_size)
2726 self.assertEqual(0, ent.offset)
2727
2728 ent = entries[4]
2729 self.assertEqual(3, ent.indent)
2730 self.assertEqual('u-boot', ent.name)
2731 self.assertEqual('u-boot', ent.etype)
2732 self.assertEqual(len(U_BOOT_DATA), ent.size)
2733 self.assertEqual(0x138, ent.image_pos)
2734 self.assertEqual(None, ent.uncomp_size)
2735 self.assertEqual(0x38, ent.offset)
2736
2737 ent = entries[5]
2738 self.assertEqual(3, ent.indent)
2739 self.assertEqual('u-boot-dtb', ent.name)
2740 self.assertEqual('text', ent.etype)
2741 self.assertGreater(len(COMPRESS_DATA), ent.size)
2742 self.assertEqual(0x178, ent.image_pos)
2743 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2744 self.assertEqual(0x78, ent.offset)
2745
2746 ent = entries[6]
2747 self.assertEqual(2, ent.indent)
2748 self.assertEqual('u-boot-dtb', ent.name)
2749 self.assertEqual('u-boot-dtb', ent.etype)
2750 self.assertEqual(0x500, ent.image_pos)
2751 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2752 dtb_size = ent.size
2753 # Compressing this data expands it since headers are added
2754 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2755 self.assertEqual(0x400, ent.offset)
2756
2757 self.assertEqual(len(data), 0x100 + section_size)
2758 self.assertEqual(section_size, 0x400 + dtb_size)
2759
Simon Glasse1925fa2019-07-08 14:25:44 -06002760 def testFindFdtmap(self):
2761 """Test locating an FDT map in an image"""
2762 self._CheckLz4()
2763 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2764 image = control.images['image']
2765 entries = image.GetEntries()
2766 entry = entries['fdtmap']
2767 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2768
2769 def testFindFdtmapMissing(self):
2770 """Test failing to locate an FDP map"""
2771 data = self._DoReadFile('005_simple.dts')
2772 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2773
Simon Glass2d260032019-07-08 14:25:45 -06002774 def testFindImageHeader(self):
2775 """Test locating a image header"""
2776 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002777 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002778 image = control.images['image']
2779 entries = image.GetEntries()
2780 entry = entries['fdtmap']
2781 # The header should point to the FDT map
2782 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2783
2784 def testFindImageHeaderStart(self):
2785 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002786 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002787 image = control.images['image']
2788 entries = image.GetEntries()
2789 entry = entries['fdtmap']
2790 # The header should point to the FDT map
2791 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2792
2793 def testFindImageHeaderMissing(self):
2794 """Test failing to locate an image header"""
2795 data = self._DoReadFile('005_simple.dts')
2796 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2797
Simon Glassffded752019-07-08 14:25:46 -06002798 def testReadImage(self):
2799 """Test reading an image and accessing its FDT map"""
2800 self._CheckLz4()
2801 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002802 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002803 orig_image = control.images['image']
2804 image = Image.FromFile(image_fname)
2805 self.assertEqual(orig_image.GetEntries().keys(),
2806 image.GetEntries().keys())
2807
2808 orig_entry = orig_image.GetEntries()['fdtmap']
2809 entry = image.GetEntries()['fdtmap']
2810 self.assertEquals(orig_entry.offset, entry.offset)
2811 self.assertEquals(orig_entry.size, entry.size)
2812 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2813
2814 def testReadImageNoHeader(self):
2815 """Test accessing an image's FDT map without an image header"""
2816 self._CheckLz4()
2817 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002818 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002819 image = Image.FromFile(image_fname)
2820 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002821 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002822
2823 def testReadImageFail(self):
2824 """Test failing to read an image image's FDT map"""
2825 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002826 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002827 with self.assertRaises(ValueError) as e:
2828 image = Image.FromFile(image_fname)
2829 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002830
Simon Glass61f564d2019-07-08 14:25:48 -06002831 def testListCmd(self):
2832 """Test listing the files in an image using an Fdtmap"""
2833 self._CheckLz4()
2834 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2835
2836 # lz4 compression size differs depending on the version
2837 image = control.images['image']
2838 entries = image.GetEntries()
2839 section_size = entries['section'].size
2840 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2841 fdtmap_offset = entries['fdtmap'].offset
2842
Simon Glassf86a7362019-07-20 12:24:10 -06002843 try:
2844 tmpdir, updated_fname = self._SetupImageInTmpdir()
2845 with test_util.capture_sys_output() as (stdout, stderr):
2846 self._DoBinman('ls', '-i', updated_fname)
2847 finally:
2848 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002849 lines = stdout.getvalue().splitlines()
2850 expected = [
2851'Name Image-pos Size Entry-type Offset Uncomp-size',
2852'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002853'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002854' u-boot 0 4 u-boot 0',
2855' section 100 %x section 100' % section_size,
2856' cbfs 100 400 cbfs 0',
Simon Glassab326012023-10-14 14:40:28 -06002857' u-boot 120 4 u-boot 20',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002858' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002859' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002860' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002861 (fdtmap_offset, fdtmap_offset),
2862' image-header bf8 8 image-header bf8',
2863 ]
2864 self.assertEqual(expected, lines)
2865
2866 def testListCmdFail(self):
2867 """Test failing to list an image"""
2868 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002869 try:
2870 tmpdir, updated_fname = self._SetupImageInTmpdir()
2871 with self.assertRaises(ValueError) as e:
2872 self._DoBinman('ls', '-i', updated_fname)
2873 finally:
2874 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002875 self.assertIn("Cannot find FDT map in image", str(e.exception))
2876
2877 def _RunListCmd(self, paths, expected):
2878 """List out entries and check the result
2879
2880 Args:
2881 paths: List of paths to pass to the list command
2882 expected: Expected list of filenames to be returned, in order
2883 """
2884 self._CheckLz4()
2885 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002886 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002887 image = Image.FromFile(image_fname)
2888 lines = image.GetListEntries(paths)[1]
2889 files = [line[0].strip() for line in lines[1:]]
2890 self.assertEqual(expected, files)
2891
2892 def testListCmdSection(self):
2893 """Test listing the files in a section"""
2894 self._RunListCmd(['section'],
2895 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2896
2897 def testListCmdFile(self):
2898 """Test listing a particular file"""
2899 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2900
2901 def testListCmdWildcard(self):
2902 """Test listing a wildcarded file"""
2903 self._RunListCmd(['*boot*'],
2904 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2905
2906 def testListCmdWildcardMulti(self):
2907 """Test listing a wildcarded file"""
2908 self._RunListCmd(['*cb*', '*head*'],
2909 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2910
2911 def testListCmdEmpty(self):
2912 """Test listing a wildcarded file"""
2913 self._RunListCmd(['nothing'], [])
2914
2915 def testListCmdPath(self):
2916 """Test listing the files in a sub-entry of a section"""
2917 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2918
Simon Glassf667e452019-07-08 14:25:50 -06002919 def _RunExtractCmd(self, entry_name, decomp=True):
2920 """Extract an entry from an image
2921
2922 Args:
2923 entry_name: Entry name to extract
2924 decomp: True to decompress the data if compressed, False to leave
2925 it in its raw uncompressed format
2926
2927 Returns:
2928 data from entry
2929 """
2930 self._CheckLz4()
2931 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002932 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002933 return control.ReadEntry(image_fname, entry_name, decomp)
2934
2935 def testExtractSimple(self):
2936 """Test extracting a single file"""
2937 data = self._RunExtractCmd('u-boot')
2938 self.assertEqual(U_BOOT_DATA, data)
2939
Simon Glass71ce0ba2019-07-08 14:25:52 -06002940 def testExtractSection(self):
2941 """Test extracting the files in a section"""
2942 data = self._RunExtractCmd('section')
2943 cbfs_data = data[:0x400]
2944 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002945 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002946 dtb_data = data[0x400:]
2947 dtb = self._decompress(dtb_data)
2948 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2949
2950 def testExtractCompressed(self):
2951 """Test extracting compressed data"""
2952 data = self._RunExtractCmd('section/u-boot-dtb')
2953 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2954
2955 def testExtractRaw(self):
2956 """Test extracting compressed data without decompressing it"""
2957 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2958 dtb = self._decompress(data)
2959 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2960
2961 def testExtractCbfs(self):
2962 """Test extracting CBFS data"""
2963 data = self._RunExtractCmd('section/cbfs/u-boot')
2964 self.assertEqual(U_BOOT_DATA, data)
2965
2966 def testExtractCbfsCompressed(self):
2967 """Test extracting CBFS compressed data"""
2968 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2969 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2970
2971 def testExtractCbfsRaw(self):
2972 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002973 bintool = self.comp_bintools['lzma_alone']
2974 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002975 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002976 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002977 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2978
Simon Glassf667e452019-07-08 14:25:50 -06002979 def testExtractBadEntry(self):
2980 """Test extracting a bad section path"""
2981 with self.assertRaises(ValueError) as e:
2982 self._RunExtractCmd('section/does-not-exist')
2983 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2984 str(e.exception))
2985
2986 def testExtractMissingFile(self):
2987 """Test extracting file that does not exist"""
2988 with self.assertRaises(IOError) as e:
2989 control.ReadEntry('missing-file', 'name')
2990
2991 def testExtractBadFile(self):
2992 """Test extracting an invalid file"""
2993 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002994 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002995 with self.assertRaises(ValueError) as e:
2996 control.ReadEntry(fname, 'name')
2997
Simon Glass71ce0ba2019-07-08 14:25:52 -06002998 def testExtractCmd(self):
2999 """Test extracting a file fron an image on the command line"""
3000 self._CheckLz4()
3001 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003002 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06003003 try:
3004 tmpdir, updated_fname = self._SetupImageInTmpdir()
3005 with test_util.capture_sys_output() as (stdout, stderr):
3006 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3007 '-f', fname)
3008 finally:
3009 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003010 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003011 self.assertEqual(U_BOOT_DATA, data)
3012
3013 def testExtractOneEntry(self):
3014 """Test extracting a single entry fron an image """
3015 self._CheckLz4()
3016 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003017 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003018 fname = os.path.join(self._indir, 'output.extact')
3019 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07003020 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003021 self.assertEqual(U_BOOT_DATA, data)
3022
3023 def _CheckExtractOutput(self, decomp):
3024 """Helper to test file output with and without decompression
3025
3026 Args:
3027 decomp: True to decompress entry data, False to output it raw
3028 """
3029 def _CheckPresent(entry_path, expect_data, expect_size=None):
3030 """Check and remove expected file
3031
3032 This checks the data/size of a file and removes the file both from
3033 the outfiles set and from the output directory. Once all files are
3034 processed, both the set and directory should be empty.
3035
3036 Args:
3037 entry_path: Entry path
3038 expect_data: Data to expect in file, or None to skip check
3039 expect_size: Size of data to expect in file, or None to skip
3040 """
3041 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003042 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003043 os.remove(path)
3044 if expect_data:
3045 self.assertEqual(expect_data, data)
3046 elif expect_size:
3047 self.assertEqual(expect_size, len(data))
3048 outfiles.remove(path)
3049
3050 def _CheckDirPresent(name):
3051 """Remove expected directory
3052
3053 This gives an error if the directory does not exist as expected
3054
3055 Args:
3056 name: Name of directory to remove
3057 """
3058 path = os.path.join(outdir, name)
3059 os.rmdir(path)
3060
3061 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003062 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003063 outdir = os.path.join(self._indir, 'extract')
3064 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3065
3066 # Create a set of all file that were output (should be 9)
3067 outfiles = set()
3068 for root, dirs, files in os.walk(outdir):
3069 outfiles |= set([os.path.join(root, fname) for fname in files])
3070 self.assertEqual(9, len(outfiles))
3071 self.assertEqual(9, len(einfos))
3072
3073 image = control.images['image']
3074 entries = image.GetEntries()
3075
3076 # Check the 9 files in various ways
3077 section = entries['section']
3078 section_entries = section.GetEntries()
3079 cbfs_entries = section_entries['cbfs'].GetEntries()
3080 _CheckPresent('u-boot', U_BOOT_DATA)
3081 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3082 dtb_len = EXTRACT_DTB_SIZE
3083 if not decomp:
3084 dtb_len = cbfs_entries['u-boot-dtb'].size
3085 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3086 if not decomp:
3087 dtb_len = section_entries['u-boot-dtb'].size
3088 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3089
3090 fdtmap = entries['fdtmap']
3091 _CheckPresent('fdtmap', fdtmap.data)
3092 hdr = entries['image-header']
3093 _CheckPresent('image-header', hdr.data)
3094
3095 _CheckPresent('section/root', section.data)
3096 cbfs = section_entries['cbfs']
3097 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003098 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003099 _CheckPresent('root', data)
3100
3101 # There should be no files left. Remove all the directories to check.
3102 # If there are any files/dirs remaining, one of these checks will fail.
3103 self.assertEqual(0, len(outfiles))
3104 _CheckDirPresent('section/cbfs')
3105 _CheckDirPresent('section')
3106 _CheckDirPresent('')
3107 self.assertFalse(os.path.exists(outdir))
3108
3109 def testExtractAllEntries(self):
3110 """Test extracting all entries"""
3111 self._CheckLz4()
3112 self._CheckExtractOutput(decomp=True)
3113
3114 def testExtractAllEntriesRaw(self):
3115 """Test extracting all entries without decompressing them"""
3116 self._CheckLz4()
3117 self._CheckExtractOutput(decomp=False)
3118
3119 def testExtractSelectedEntries(self):
3120 """Test extracting some entries"""
3121 self._CheckLz4()
3122 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003123 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003124 outdir = os.path.join(self._indir, 'extract')
3125 einfos = control.ExtractEntries(image_fname, None, outdir,
3126 ['*cb*', '*head*'])
3127
3128 # File output is tested by testExtractAllEntries(), so just check that
3129 # the expected entries are selected
3130 names = [einfo.name for einfo in einfos]
3131 self.assertEqual(names,
3132 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3133
3134 def testExtractNoEntryPaths(self):
3135 """Test extracting some entries"""
3136 self._CheckLz4()
3137 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003138 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003139 with self.assertRaises(ValueError) as e:
3140 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003141 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003142 str(e.exception))
3143
3144 def testExtractTooManyEntryPaths(self):
3145 """Test extracting some entries"""
3146 self._CheckLz4()
3147 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003148 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003149 with self.assertRaises(ValueError) as e:
3150 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003151 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003152 str(e.exception))
3153
Simon Glasse2705fa2019-07-08 14:25:53 -06003154 def testPackAlignSection(self):
3155 """Test that sections can have alignment"""
3156 self._DoReadFile('131_pack_align_section.dts')
3157
3158 self.assertIn('image', control.images)
3159 image = control.images['image']
3160 entries = image.GetEntries()
3161 self.assertEqual(3, len(entries))
3162
3163 # First u-boot
3164 self.assertIn('u-boot', entries)
3165 entry = entries['u-boot']
3166 self.assertEqual(0, entry.offset)
3167 self.assertEqual(0, entry.image_pos)
3168 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3169 self.assertEqual(len(U_BOOT_DATA), entry.size)
3170
3171 # Section0
3172 self.assertIn('section0', entries)
3173 section0 = entries['section0']
3174 self.assertEqual(0x10, section0.offset)
3175 self.assertEqual(0x10, section0.image_pos)
3176 self.assertEqual(len(U_BOOT_DATA), section0.size)
3177
3178 # Second u-boot
3179 section_entries = section0.GetEntries()
3180 self.assertIn('u-boot', section_entries)
3181 entry = section_entries['u-boot']
3182 self.assertEqual(0, entry.offset)
3183 self.assertEqual(0x10, entry.image_pos)
3184 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3185 self.assertEqual(len(U_BOOT_DATA), entry.size)
3186
3187 # Section1
3188 self.assertIn('section1', entries)
3189 section1 = entries['section1']
3190 self.assertEqual(0x14, section1.offset)
3191 self.assertEqual(0x14, section1.image_pos)
3192 self.assertEqual(0x20, section1.size)
3193
3194 # Second u-boot
3195 section_entries = section1.GetEntries()
3196 self.assertIn('u-boot', section_entries)
3197 entry = section_entries['u-boot']
3198 self.assertEqual(0, entry.offset)
3199 self.assertEqual(0x14, entry.image_pos)
3200 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3201 self.assertEqual(len(U_BOOT_DATA), entry.size)
3202
3203 # Section2
3204 self.assertIn('section2', section_entries)
3205 section2 = section_entries['section2']
3206 self.assertEqual(0x4, section2.offset)
3207 self.assertEqual(0x18, section2.image_pos)
3208 self.assertEqual(4, section2.size)
3209
3210 # Third u-boot
3211 section_entries = section2.GetEntries()
3212 self.assertIn('u-boot', section_entries)
3213 entry = section_entries['u-boot']
3214 self.assertEqual(0, entry.offset)
3215 self.assertEqual(0x18, entry.image_pos)
3216 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3217 self.assertEqual(len(U_BOOT_DATA), entry.size)
3218
Simon Glass51014aa2019-07-20 12:23:56 -06003219 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3220 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003221 """Replace an entry in an image
3222
3223 This writes the entry data to update it, then opens the updated file and
3224 returns the value that it now finds there.
3225
3226 Args:
3227 entry_name: Entry name to replace
3228 data: Data to replace it with
3229 decomp: True to compress the data if needed, False if data is
3230 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003231 allow_resize: True to allow entries to change size, False to raise
3232 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003233
3234 Returns:
3235 Tuple:
3236 data from entry
3237 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003238 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003239 """
Simon Glass51014aa2019-07-20 12:23:56 -06003240 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003241 update_dtb=True)[1]
3242
3243 self.assertIn('image', control.images)
3244 image = control.images['image']
3245 entries = image.GetEntries()
3246 orig_dtb_data = entries['u-boot-dtb'].data
3247 orig_fdtmap_data = entries['fdtmap'].data
3248
Simon Glassc1aa66e2022-01-29 14:14:04 -07003249 image_fname = tools.get_output_filename('image.bin')
3250 updated_fname = tools.get_output_filename('image-updated.bin')
3251 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003252 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3253 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003254 data = control.ReadEntry(updated_fname, entry_name, decomp)
3255
Simon Glass51014aa2019-07-20 12:23:56 -06003256 # The DT data should not change unless resized:
3257 if not allow_resize:
3258 new_dtb_data = entries['u-boot-dtb'].data
3259 self.assertEqual(new_dtb_data, orig_dtb_data)
3260 new_fdtmap_data = entries['fdtmap'].data
3261 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003262
Simon Glass51014aa2019-07-20 12:23:56 -06003263 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003264
3265 def testReplaceSimple(self):
3266 """Test replacing a single file"""
3267 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003268 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3269 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003270 self.assertEqual(expected, data)
3271
3272 # Test that the state looks right. There should be an FDT for the fdtmap
3273 # that we jsut read back in, and it should match what we find in the
3274 # 'control' tables. Checking for an FDT that does not exist should
3275 # return None.
3276 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003277 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003278 self.assertEqual(expected_fdtmap, fdtmap)
3279
3280 dtb = state.GetFdtForEtype('fdtmap')
3281 self.assertEqual(dtb.GetContents(), fdtmap)
3282
3283 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3284 self.assertIsNone(missing_path)
3285 self.assertIsNone(missing_fdtmap)
3286
3287 missing_dtb = state.GetFdtForEtype('missing')
3288 self.assertIsNone(missing_dtb)
3289
3290 self.assertEqual('/binman', state.fdt_path_prefix)
3291
3292 def testReplaceResizeFail(self):
3293 """Test replacing a file by something larger"""
3294 expected = U_BOOT_DATA + b'x'
3295 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003296 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3297 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003298 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3299 str(e.exception))
3300
3301 def testReplaceMulti(self):
3302 """Test replacing entry data where multiple images are generated"""
3303 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3304 update_dtb=True)[0]
3305 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003306 updated_fname = tools.get_output_filename('image-updated.bin')
3307 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003308 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003309 control.WriteEntry(updated_fname, entry_name, expected,
3310 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003311 data = control.ReadEntry(updated_fname, entry_name)
3312 self.assertEqual(expected, data)
3313
3314 # Check the state looks right.
3315 self.assertEqual('/binman/image', state.fdt_path_prefix)
3316
3317 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003318 image_fname = tools.get_output_filename('first-image.bin')
3319 updated_fname = tools.get_output_filename('first-updated.bin')
3320 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003321 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003322 control.WriteEntry(updated_fname, entry_name, expected,
3323 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003324 data = control.ReadEntry(updated_fname, entry_name)
3325 self.assertEqual(expected, data)
3326
3327 # Check the state looks right.
3328 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003329
Simon Glass12bb1a92019-07-20 12:23:51 -06003330 def testUpdateFdtAllRepack(self):
3331 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003332 self._SetupSplElf()
3333 self._SetupTplElf()
Simon Glass12bb1a92019-07-20 12:23:51 -06003334 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3335 SECTION_SIZE = 0x300
3336 DTB_SIZE = 602
3337 FDTMAP_SIZE = 608
3338 base_expected = {
3339 'offset': 0,
3340 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3341 'image-pos': 0,
3342 'section:offset': 0,
3343 'section:size': SECTION_SIZE,
3344 'section:image-pos': 0,
3345 'section/u-boot-dtb:offset': 4,
3346 'section/u-boot-dtb:size': 636,
3347 'section/u-boot-dtb:image-pos': 4,
3348 'u-boot-spl-dtb:offset': SECTION_SIZE,
3349 'u-boot-spl-dtb:size': DTB_SIZE,
3350 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3351 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3352 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3353 'u-boot-tpl-dtb:size': DTB_SIZE,
3354 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3355 'fdtmap:size': FDTMAP_SIZE,
3356 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3357 }
3358 main_expected = {
3359 'section:orig-size': SECTION_SIZE,
3360 'section/u-boot-dtb:orig-offset': 4,
3361 }
3362
3363 # We expect three device-tree files in the output, with the first one
3364 # within a fixed-size section.
3365 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3366 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3367 # main U-Boot tree. All three should have the same positions and offset
3368 # except that the main tree should include the main_expected properties
3369 start = 4
3370 for item in ['', 'spl', 'tpl', None]:
3371 if item is None:
3372 start += 16 # Move past fdtmap header
3373 dtb = fdt.Fdt.FromData(data[start:])
3374 dtb.Scan()
3375 props = self._GetPropTree(dtb,
3376 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3377 prefix='/' if item is None else '/binman/')
3378 expected = dict(base_expected)
3379 if item:
3380 expected[item] = 0
3381 else:
3382 # Main DTB and fdtdec should include the 'orig-' properties
3383 expected.update(main_expected)
3384 # Helpful for debugging:
3385 #for prop in sorted(props):
3386 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3387 self.assertEqual(expected, props)
3388 if item == '':
3389 start = SECTION_SIZE
3390 else:
3391 start += dtb._fdt_obj.totalsize()
3392
Simon Glasseba1f0c2019-07-20 12:23:55 -06003393 def testFdtmapHeaderMiddle(self):
3394 """Test an FDT map in the middle of an image when it should be at end"""
3395 with self.assertRaises(ValueError) as e:
3396 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3397 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3398 str(e.exception))
3399
3400 def testFdtmapHeaderStartBad(self):
3401 """Test an FDT map in middle of an image when it should be at start"""
3402 with self.assertRaises(ValueError) as e:
3403 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3404 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3405 str(e.exception))
3406
3407 def testFdtmapHeaderEndBad(self):
3408 """Test an FDT map at the start of an image when it should be at end"""
3409 with self.assertRaises(ValueError) as e:
3410 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3411 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3412 str(e.exception))
3413
3414 def testFdtmapHeaderNoSize(self):
3415 """Test an image header at the end of an image with undefined size"""
3416 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3417
Simon Glass51014aa2019-07-20 12:23:56 -06003418 def testReplaceResize(self):
3419 """Test replacing a single file in an entry with a larger file"""
3420 expected = U_BOOT_DATA + b'x'
3421 data, _, image = self._RunReplaceCmd('u-boot', expected,
3422 dts='139_replace_repack.dts')
3423 self.assertEqual(expected, data)
3424
3425 entries = image.GetEntries()
3426 dtb_data = entries['u-boot-dtb'].data
3427 dtb = fdt.Fdt.FromData(dtb_data)
3428 dtb.Scan()
3429
3430 # The u-boot section should now be larger in the dtb
3431 node = dtb.GetNode('/binman/u-boot')
3432 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3433
3434 # Same for the fdtmap
3435 fdata = entries['fdtmap'].data
3436 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3437 fdtb.Scan()
3438 fnode = fdtb.GetNode('/u-boot')
3439 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3440
3441 def testReplaceResizeNoRepack(self):
3442 """Test replacing an entry with a larger file when not allowed"""
3443 expected = U_BOOT_DATA + b'x'
3444 with self.assertRaises(ValueError) as e:
3445 self._RunReplaceCmd('u-boot', expected)
3446 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3447 str(e.exception))
3448
Simon Glass61ec04f2019-07-20 12:23:58 -06003449 def testEntryShrink(self):
3450 """Test contracting an entry after it is packed"""
3451 try:
3452 state.SetAllowEntryContraction(True)
3453 data = self._DoReadFileDtb('140_entry_shrink.dts',
3454 update_dtb=True)[0]
3455 finally:
3456 state.SetAllowEntryContraction(False)
3457 self.assertEqual(b'a', data[:1])
3458 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3459 self.assertEqual(b'a', data[-1:])
3460
3461 def testEntryShrinkFail(self):
3462 """Test not being allowed to contract an entry after it is packed"""
3463 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3464
3465 # In this case there is a spare byte at the end of the data. The size of
3466 # the contents is only 1 byte but we still have the size before it
3467 # shrunk.
3468 self.assertEqual(b'a\0', data[:2])
3469 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3470 self.assertEqual(b'a\0', data[-2:])
3471
Simon Glass27145fd2019-07-20 12:24:01 -06003472 def testDescriptorOffset(self):
3473 """Test that the Intel descriptor is always placed at at the start"""
3474 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3475 image = control.images['image']
3476 entries = image.GetEntries()
3477 desc = entries['intel-descriptor']
3478 self.assertEqual(0xff800000, desc.offset);
3479 self.assertEqual(0xff800000, desc.image_pos);
3480
Simon Glasseb0f4a42019-07-20 12:24:06 -06003481 def testReplaceCbfs(self):
3482 """Test replacing a single file in CBFS without changing the size"""
3483 self._CheckLz4()
3484 expected = b'x' * len(U_BOOT_DATA)
3485 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003486 updated_fname = tools.get_output_filename('image-updated.bin')
3487 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003488 entry_name = 'section/cbfs/u-boot'
3489 control.WriteEntry(updated_fname, entry_name, expected,
3490 allow_resize=True)
3491 data = control.ReadEntry(updated_fname, entry_name)
3492 self.assertEqual(expected, data)
3493
3494 def testReplaceResizeCbfs(self):
3495 """Test replacing a single file in CBFS with one of a different size"""
3496 self._CheckLz4()
3497 expected = U_BOOT_DATA + b'x'
3498 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003499 updated_fname = tools.get_output_filename('image-updated.bin')
3500 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003501 entry_name = 'section/cbfs/u-boot'
3502 control.WriteEntry(updated_fname, entry_name, expected,
3503 allow_resize=True)
3504 data = control.ReadEntry(updated_fname, entry_name)
3505 self.assertEqual(expected, data)
3506
Simon Glassa6cb9952019-07-20 12:24:15 -06003507 def _SetupForReplace(self):
3508 """Set up some files to use to replace entries
3509
3510 This generates an image, copies it to a new file, extracts all the files
3511 in it and updates some of them
3512
3513 Returns:
3514 List
3515 Image filename
3516 Output directory
3517 Expected values for updated entries, each a string
3518 """
3519 data = self._DoReadFileRealDtb('143_replace_all.dts')
3520
Simon Glassc1aa66e2022-01-29 14:14:04 -07003521 updated_fname = tools.get_output_filename('image-updated.bin')
3522 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003523
3524 outdir = os.path.join(self._indir, 'extract')
3525 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3526
3527 expected1 = b'x' + U_BOOT_DATA + b'y'
3528 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003529 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003530
3531 expected2 = b'a' + U_BOOT_DATA + b'b'
3532 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003533 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003534
3535 expected_text = b'not the same text'
3536 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003537 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003538
3539 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3540 dtb = fdt.FdtScan(dtb_fname)
3541 node = dtb.GetNode('/binman/text')
3542 node.AddString('my-property', 'the value')
3543 dtb.Sync(auto_resize=True)
3544 dtb.Flush()
3545
3546 return updated_fname, outdir, expected1, expected2, expected_text
3547
3548 def _CheckReplaceMultiple(self, entry_paths):
3549 """Handle replacing the contents of multiple entries
3550
3551 Args:
3552 entry_paths: List of entry paths to replace
3553
3554 Returns:
3555 List
3556 Dict of entries in the image:
3557 key: Entry name
3558 Value: Entry object
3559 Expected values for updated entries, each a string
3560 """
3561 updated_fname, outdir, expected1, expected2, expected_text = (
3562 self._SetupForReplace())
3563 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3564
3565 image = Image.FromFile(updated_fname)
3566 image.LoadData()
3567 return image.GetEntries(), expected1, expected2, expected_text
3568
3569 def testReplaceAll(self):
3570 """Test replacing the contents of all entries"""
3571 entries, expected1, expected2, expected_text = (
3572 self._CheckReplaceMultiple([]))
3573 data = entries['u-boot'].data
3574 self.assertEqual(expected1, data)
3575
3576 data = entries['u-boot2'].data
3577 self.assertEqual(expected2, data)
3578
3579 data = entries['text'].data
3580 self.assertEqual(expected_text, data)
3581
3582 # Check that the device tree is updated
3583 data = entries['u-boot-dtb'].data
3584 dtb = fdt.Fdt.FromData(data)
3585 dtb.Scan()
3586 node = dtb.GetNode('/binman/text')
3587 self.assertEqual('the value', node.props['my-property'].value)
3588
3589 def testReplaceSome(self):
3590 """Test replacing the contents of a few entries"""
3591 entries, expected1, expected2, expected_text = (
3592 self._CheckReplaceMultiple(['u-boot2', 'text']))
3593
3594 # This one should not change
3595 data = entries['u-boot'].data
3596 self.assertEqual(U_BOOT_DATA, data)
3597
3598 data = entries['u-boot2'].data
3599 self.assertEqual(expected2, data)
3600
3601 data = entries['text'].data
3602 self.assertEqual(expected_text, data)
3603
3604 def testReplaceCmd(self):
3605 """Test replacing a file fron an image on the command line"""
3606 self._DoReadFileRealDtb('143_replace_all.dts')
3607
3608 try:
3609 tmpdir, updated_fname = self._SetupImageInTmpdir()
3610
3611 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3612 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003613 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003614
3615 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003616 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003617 self.assertEqual(expected, data[:len(expected)])
3618 map_fname = os.path.join(tmpdir, 'image-updated.map')
3619 self.assertFalse(os.path.exists(map_fname))
3620 finally:
3621 shutil.rmtree(tmpdir)
3622
3623 def testReplaceCmdSome(self):
3624 """Test replacing some files fron an image on the command line"""
3625 updated_fname, outdir, expected1, expected2, expected_text = (
3626 self._SetupForReplace())
3627
3628 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3629 'u-boot2', 'text')
3630
Simon Glassc1aa66e2022-01-29 14:14:04 -07003631 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003632 image = Image.FromFile(updated_fname)
3633 image.LoadData()
3634 entries = image.GetEntries()
3635
3636 # This one should not change
3637 data = entries['u-boot'].data
3638 self.assertEqual(U_BOOT_DATA, data)
3639
3640 data = entries['u-boot2'].data
3641 self.assertEqual(expected2, data)
3642
3643 data = entries['text'].data
3644 self.assertEqual(expected_text, data)
3645
3646 def testReplaceMissing(self):
3647 """Test replacing entries where the file is missing"""
3648 updated_fname, outdir, expected1, expected2, expected_text = (
3649 self._SetupForReplace())
3650
3651 # Remove one of the files, to generate a warning
3652 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3653 os.remove(u_boot_fname1)
3654
3655 with test_util.capture_sys_output() as (stdout, stderr):
3656 control.ReplaceEntries(updated_fname, None, outdir, [])
3657 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003658 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003659
3660 def testReplaceCmdMap(self):
3661 """Test replacing a file fron an image on the command line"""
3662 self._DoReadFileRealDtb('143_replace_all.dts')
3663
3664 try:
3665 tmpdir, updated_fname = self._SetupImageInTmpdir()
3666
3667 fname = os.path.join(self._indir, 'update-u-boot.bin')
3668 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003669 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003670
3671 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3672 '-f', fname, '-m')
3673 map_fname = os.path.join(tmpdir, 'image-updated.map')
3674 self.assertTrue(os.path.exists(map_fname))
3675 finally:
3676 shutil.rmtree(tmpdir)
3677
3678 def testReplaceNoEntryPaths(self):
3679 """Test replacing an entry without an entry path"""
3680 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003681 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003682 with self.assertRaises(ValueError) as e:
3683 control.ReplaceEntries(image_fname, 'fname', None, [])
3684 self.assertIn('Must specify an entry path to read with -f',
3685 str(e.exception))
3686
3687 def testReplaceTooManyEntryPaths(self):
3688 """Test extracting some entries"""
3689 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003690 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003691 with self.assertRaises(ValueError) as e:
3692 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3693 self.assertIn('Must specify exactly one entry path to write with -f',
3694 str(e.exception))
3695
Simon Glass2250ee62019-08-24 07:22:48 -06003696 def testPackReset16(self):
3697 """Test that an image with an x86 reset16 region can be created"""
3698 data = self._DoReadFile('144_x86_reset16.dts')
3699 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3700
3701 def testPackReset16Spl(self):
3702 """Test that an image with an x86 reset16-spl region can be created"""
3703 data = self._DoReadFile('145_x86_reset16_spl.dts')
3704 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3705
3706 def testPackReset16Tpl(self):
3707 """Test that an image with an x86 reset16-tpl region can be created"""
3708 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3709 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3710
Simon Glass5af12072019-08-24 07:22:50 -06003711 def testPackIntelFit(self):
3712 """Test that an image with an Intel FIT and pointer can be created"""
3713 data = self._DoReadFile('147_intel_fit.dts')
3714 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3715 fit = data[16:32];
3716 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3717 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3718
3719 image = control.images['image']
3720 entries = image.GetEntries()
3721 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3722 self.assertEqual(expected_ptr, ptr)
3723
3724 def testPackIntelFitMissing(self):
3725 """Test detection of a FIT pointer with not FIT region"""
3726 with self.assertRaises(ValueError) as e:
3727 self._DoReadFile('148_intel_fit_missing.dts')
3728 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3729 str(e.exception))
3730
Simon Glass7c150132019-11-06 17:22:44 -07003731 def _CheckSymbolsTplSection(self, dts, expected_vals):
3732 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003733 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003734 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003735 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003736 self.assertEqual(expected1, data[:upto1])
3737
3738 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003739 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003740 self.assertEqual(expected2, data[upto1:upto2])
3741
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003742 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003743 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003744 self.assertEqual(expected3, data[upto2:upto3])
3745
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003746 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003747 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3748
3749 def testSymbolsTplSection(self):
3750 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3751 self._SetupSplElf('u_boot_binman_syms')
3752 self._SetupTplElf('u_boot_binman_syms')
3753 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003754 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003755
3756 def testSymbolsTplSectionX86(self):
3757 """Test binman can assign symbols in a section with end-at-4gb"""
3758 self._SetupSplElf('u_boot_binman_syms_x86')
3759 self._SetupTplElf('u_boot_binman_syms_x86')
3760 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003761 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003762 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003763
Simon Glassbf4d0e22019-08-24 07:23:03 -06003764 def testPackX86RomIfwiSectiom(self):
3765 """Test that a section can be placed in an IFWI region"""
3766 self._SetupIfwi('fitimage.bin')
3767 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3768 self._CheckIfwi(data)
3769
Simon Glassea0fff92019-08-24 07:23:07 -06003770 def testPackFspM(self):
3771 """Test that an image with a FSP memory-init binary can be created"""
3772 data = self._DoReadFile('152_intel_fsp_m.dts')
3773 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3774
Simon Glassbc6a88f2019-10-20 21:31:35 -06003775 def testPackFspS(self):
3776 """Test that an image with a FSP silicon-init binary can be created"""
3777 data = self._DoReadFile('153_intel_fsp_s.dts')
3778 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003779
Simon Glass998d1482019-10-20 21:31:36 -06003780 def testPackFspT(self):
3781 """Test that an image with a FSP temp-ram-init binary can be created"""
3782 data = self._DoReadFile('154_intel_fsp_t.dts')
3783 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3784
Simon Glass0dc706f2020-07-09 18:39:31 -06003785 def testMkimage(self):
3786 """Test using mkimage to build an image"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003787 self._SetupSplElf()
Simon Glass0dc706f2020-07-09 18:39:31 -06003788 data = self._DoReadFile('156_mkimage.dts')
3789
3790 # Just check that the data appears in the file somewhere
3791 self.assertIn(U_BOOT_SPL_DATA, data)
3792
Simon Glass4f9ee832022-01-09 20:14:09 -07003793 def testMkimageMissing(self):
3794 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003795 self._SetupSplElf()
Simon Glass4f9ee832022-01-09 20:14:09 -07003796 with test_util.capture_sys_output() as (_, stderr):
3797 self._DoTestFile('156_mkimage.dts',
3798 force_missing_bintools='mkimage')
3799 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003800 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003801
Simon Glassce867ad2020-07-09 18:39:36 -06003802 def testExtblob(self):
3803 """Test an image with an external blob"""
3804 data = self._DoReadFile('157_blob_ext.dts')
3805 self.assertEqual(REFCODE_DATA, data)
3806
3807 def testExtblobMissing(self):
3808 """Test an image with a missing external blob"""
3809 with self.assertRaises(ValueError) as e:
3810 self._DoReadFile('158_blob_ext_missing.dts')
3811 self.assertIn("Filename 'missing-file' not found in input path",
3812 str(e.exception))
3813
Simon Glass4f9f1052020-07-09 18:39:38 -06003814 def testExtblobMissingOk(self):
3815 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003816 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003817 ret = self._DoTestFile('158_blob_ext_missing.dts',
3818 allow_missing=True)
3819 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003820 err = stderr.getvalue()
Jonas Karlman8f452bc2023-07-18 20:34:39 +00003821 self.assertIn('(missing-file)', err)
Simon Glass193d3db2023-02-07 14:34:18 -07003822 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003823 self.assertIn('Some images are invalid', err)
3824
3825 def testExtblobMissingOkFlag(self):
3826 """Test an image with an missing external blob allowed with -W"""
3827 with test_util.capture_sys_output() as (stdout, stderr):
3828 ret = self._DoTestFile('158_blob_ext_missing.dts',
3829 allow_missing=True, ignore_missing=True)
3830 self.assertEqual(0, ret)
3831 err = stderr.getvalue()
Jonas Karlman8f452bc2023-07-18 20:34:39 +00003832 self.assertIn('(missing-file)', err)
Simon Glass193d3db2023-02-07 14:34:18 -07003833 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003834 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003835
3836 def testExtblobMissingOkSect(self):
3837 """Test an image with an missing external blob that is allowed"""
3838 with test_util.capture_sys_output() as (stdout, stderr):
3839 self._DoTestFile('159_blob_ext_missing_sect.dts',
3840 allow_missing=True)
3841 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003842 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003843
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003844 def testPackX86RomMeMissingDesc(self):
3845 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003846 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003847 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003848 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003849 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003850
3851 def testPackX86RomMissingIfwi(self):
3852 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3853 self._SetupIfwi('fitimage.bin')
3854 pathname = os.path.join(self._indir, 'fitimage.bin')
3855 os.remove(pathname)
3856 with test_util.capture_sys_output() as (stdout, stderr):
3857 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3858 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003859 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003860
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003861 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003862 """Test that zero-size overlapping regions are ignored"""
3863 self._DoTestFile('160_pack_overlap_zero.dts')
3864
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003865 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003866 # The data should be inside the FIT
3867 dtb = fdt.Fdt.FromData(fit_data)
3868 dtb.Scan()
3869 fnode = dtb.GetNode('/images/kernel')
3870 self.assertIn('data', fnode.props)
3871
3872 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003873 tools.write_file(fname, fit_data)
3874 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003875
3876 # Check a few features to make sure the plumbing works. We don't need
3877 # to test the operation of mkimage or dumpimage here. First convert the
3878 # output into a dict where the keys are the fields printed by dumpimage
3879 # and the values are a list of values for each field
3880 lines = out.splitlines()
3881
3882 # Converts "Compression: gzip compressed" into two groups:
3883 # 'Compression' and 'gzip compressed'
3884 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3885 vals = collections.defaultdict(list)
3886 for line in lines:
3887 mat = re_line.match(line)
3888 vals[mat.group(1)].append(mat.group(2))
3889
3890 self.assertEquals('FIT description: test-desc', lines[0])
3891 self.assertIn('Created:', lines[1])
3892 self.assertIn('Image 0 (kernel)', vals)
3893 self.assertIn('Hash value', vals)
3894 data_sizes = vals.get('Data Size')
3895 self.assertIsNotNone(data_sizes)
3896 self.assertEqual(2, len(data_sizes))
3897 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003898 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3899 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3900
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003901 # Check if entry listing correctly omits /images/
3902 image = control.images['image']
3903 fit_entry = image.GetEntries()['fit']
3904 subentries = list(fit_entry.GetEntries().keys())
3905 expected = ['kernel', 'fdt-1']
3906 self.assertEqual(expected, subentries)
3907
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003908 def testSimpleFit(self):
3909 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003910 self._SetupSplElf()
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003911 data = self._DoReadFile('161_fit.dts')
3912 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3913 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3914 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3915
3916 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3917
3918 def testSimpleFitExpandsSubentries(self):
3919 """Test that FIT images expand their subentries"""
3920 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3921 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3922 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3923 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3924
3925 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003926
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003927 def testSimpleFitImagePos(self):
3928 """Test that we have correct image-pos for FIT subentries"""
3929 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3930 update_dtb=True)
3931 dtb = fdt.Fdt(out_dtb_fname)
3932 dtb.Scan()
3933 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3934
Simon Glass38397d02022-03-05 20:19:01 -07003935 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003936 self.assertEqual({
3937 'image-pos': 0,
3938 'offset': 0,
3939 'size': 1890,
3940
3941 'u-boot:image-pos': 0,
3942 'u-boot:offset': 0,
3943 'u-boot:size': 4,
3944
3945 'fit:image-pos': 4,
3946 'fit:offset': 4,
3947 'fit:size': 1840,
3948
Simon Glass38397d02022-03-05 20:19:01 -07003949 'fit/images/kernel:image-pos': 304,
3950 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003951 'fit/images/kernel:size': 4,
3952
Simon Glass38397d02022-03-05 20:19:01 -07003953 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003954 'fit/images/kernel/u-boot:offset': 0,
3955 'fit/images/kernel/u-boot:size': 4,
3956
Simon Glass38397d02022-03-05 20:19:01 -07003957 'fit/images/fdt-1:image-pos': 552,
3958 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003959 'fit/images/fdt-1:size': 6,
3960
Simon Glass38397d02022-03-05 20:19:01 -07003961 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003962 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3963 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3964
3965 'u-boot-nodtb:image-pos': 1844,
3966 'u-boot-nodtb:offset': 1844,
3967 'u-boot-nodtb:size': 46,
3968 }, props)
3969
3970 # Actually check the data is where we think it is
3971 for node, expected in [
3972 ("u-boot", U_BOOT_DATA),
3973 ("fit/images/kernel", U_BOOT_DATA),
3974 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3975 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3976 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3977 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3978 ]:
3979 image_pos = props[f"{node}:image-pos"]
3980 size = props[f"{node}:size"]
3981 self.assertEqual(len(expected), size)
3982 self.assertEqual(expected, data[image_pos:image_pos+size])
3983
Simon Glassfdc34362020-07-09 18:39:45 -06003984 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003985 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003986 data = self._DoReadFile('162_fit_external.dts')
3987 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3988
Simon Glass8bc78b72022-01-09 20:13:39 -07003989 # Size of the external-data region as set up by mkimage
3990 external_data_size = len(U_BOOT_DATA) + 2
3991 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003992 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003993 len(U_BOOT_NODTB_DATA))
3994
Simon Glassfdc34362020-07-09 18:39:45 -06003995 # The data should be outside the FIT
3996 dtb = fdt.Fdt.FromData(fit_data)
3997 dtb.Scan()
3998 fnode = dtb.GetNode('/images/kernel')
3999 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07004000 self.assertEqual(len(U_BOOT_DATA),
4001 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4002 fit_pos = 0x400;
4003 self.assertEqual(
4004 fit_pos,
4005 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4006
4007 self.assertEquals(expected_size, len(data))
4008 actual_pos = len(U_BOOT_DATA) + fit_pos
4009 self.assertEqual(U_BOOT_DATA + b'aa',
4010 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06004011
Alper Nebi Yasak73092222022-02-08 01:08:08 +03004012 def testFitExternalImagePos(self):
4013 """Test that we have correct image-pos for external FIT subentries"""
4014 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4015 update_dtb=True)
4016 dtb = fdt.Fdt(out_dtb_fname)
4017 dtb.Scan()
4018 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4019
4020 self.assertEqual({
4021 'image-pos': 0,
4022 'offset': 0,
4023 'size': 1082,
4024
4025 'u-boot:image-pos': 0,
4026 'u-boot:offset': 0,
4027 'u-boot:size': 4,
4028
4029 'fit:size': 1032,
4030 'fit:offset': 4,
4031 'fit:image-pos': 4,
4032
4033 'fit/images/kernel:size': 4,
4034 'fit/images/kernel:offset': 1024,
4035 'fit/images/kernel:image-pos': 1028,
4036
4037 'fit/images/kernel/u-boot:size': 4,
4038 'fit/images/kernel/u-boot:offset': 0,
4039 'fit/images/kernel/u-boot:image-pos': 1028,
4040
4041 'fit/images/fdt-1:size': 2,
4042 'fit/images/fdt-1:offset': 1028,
4043 'fit/images/fdt-1:image-pos': 1032,
4044
4045 'fit/images/fdt-1/_testing:size': 2,
4046 'fit/images/fdt-1/_testing:offset': 0,
4047 'fit/images/fdt-1/_testing:image-pos': 1032,
4048
4049 'u-boot-nodtb:image-pos': 1036,
4050 'u-boot-nodtb:offset': 1036,
4051 'u-boot-nodtb:size': 46,
4052 }, props)
4053
4054 # Actually check the data is where we think it is
4055 for node, expected in [
4056 ("u-boot", U_BOOT_DATA),
4057 ("fit/images/kernel", U_BOOT_DATA),
4058 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4059 ("fit/images/fdt-1", b'aa'),
4060 ("fit/images/fdt-1/_testing", b'aa'),
4061 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4062 ]:
4063 image_pos = props[f"{node}:image-pos"]
4064 size = props[f"{node}:size"]
4065 self.assertEqual(len(expected), size)
4066 self.assertEqual(expected, data[image_pos:image_pos+size])
4067
Simon Glass4f9ee832022-01-09 20:14:09 -07004068 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004069 """Test that binman complains if mkimage is missing"""
4070 with self.assertRaises(ValueError) as e:
4071 self._DoTestFile('162_fit_external.dts',
4072 force_missing_bintools='mkimage')
4073 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4074 str(e.exception))
4075
4076 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004077 """Test that binman still produces a FIT image if mkimage is missing"""
4078 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004079 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004080 force_missing_bintools='mkimage')
4081 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004082 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004083
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004084 def testSectionIgnoreHashSignature(self):
4085 """Test that sections ignore hash, signature nodes for its data"""
4086 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4087 expected = (U_BOOT_DATA + U_BOOT_DATA)
4088 self.assertEqual(expected, data)
4089
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004090 def testPadInSections(self):
4091 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004092 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4093 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004094 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4095 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004096 U_BOOT_DATA)
4097 self.assertEqual(expected, data)
4098
Simon Glassf90d9062020-10-26 17:40:09 -06004099 dtb = fdt.Fdt(out_dtb_fname)
4100 dtb.Scan()
4101 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4102 expected = {
4103 'image-pos': 0,
4104 'offset': 0,
4105 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4106
4107 'section:image-pos': 0,
4108 'section:offset': 0,
4109 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4110
4111 'section/before:image-pos': 0,
4112 'section/before:offset': 0,
4113 'section/before:size': len(U_BOOT_DATA),
4114
4115 'section/u-boot:image-pos': 4,
4116 'section/u-boot:offset': 4,
4117 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4118
4119 'section/after:image-pos': 26,
4120 'section/after:offset': 26,
4121 'section/after:size': len(U_BOOT_DATA),
4122 }
4123 self.assertEqual(expected, props)
4124
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004125 def testFitImageSubentryAlignment(self):
4126 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004127 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004128 entry_args = {
4129 'test-id': TEXT_DATA,
4130 }
4131 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4132 entry_args=entry_args)
4133 dtb = fdt.Fdt.FromData(data)
4134 dtb.Scan()
4135
4136 node = dtb.GetNode('/images/kernel')
4137 data = dtb.GetProps(node)["data"].bytes
4138 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004139 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4140 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004141 self.assertEqual(expected, data)
4142
4143 node = dtb.GetNode('/images/fdt-1')
4144 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004145 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4146 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004147 U_BOOT_DTB_DATA)
4148 self.assertEqual(expected, data)
4149
4150 def testFitExtblobMissingOk(self):
4151 """Test a FIT with a missing external blob that is allowed"""
4152 with test_util.capture_sys_output() as (stdout, stderr):
4153 self._DoTestFile('168_fit_missing_blob.dts',
4154 allow_missing=True)
4155 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004156 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004157
Simon Glass3decfa32020-09-01 05:13:54 -06004158 def testBlobNamedByArgMissing(self):
4159 """Test handling of a missing entry arg"""
4160 with self.assertRaises(ValueError) as e:
4161 self._DoReadFile('068_blob_named_by_arg.dts')
4162 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4163 str(e.exception))
4164
Simon Glassdc2f81a2020-09-01 05:13:58 -06004165 def testPackBl31(self):
4166 """Test that an image with an ATF BL31 binary can be created"""
4167 data = self._DoReadFile('169_atf_bl31.dts')
4168 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4169
Samuel Holland18bd4552020-10-21 21:12:15 -05004170 def testPackScp(self):
4171 """Test that an image with an SCP binary can be created"""
4172 data = self._DoReadFile('172_scp.dts')
4173 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4174
Simon Glass6cf99532020-09-01 05:13:59 -06004175 def testFitFdt(self):
4176 """Test an image with an FIT with multiple FDT images"""
4177 def _CheckFdt(seq, expected_data):
4178 """Check the FDT nodes
4179
4180 Args:
4181 seq: Sequence number to check (0 or 1)
4182 expected_data: Expected contents of 'data' property
4183 """
4184 name = 'fdt-%d' % seq
4185 fnode = dtb.GetNode('/images/%s' % name)
4186 self.assertIsNotNone(fnode)
4187 self.assertEqual({'description','type', 'compression', 'data'},
4188 set(fnode.props.keys()))
4189 self.assertEqual(expected_data, fnode.props['data'].bytes)
4190 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4191 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004192 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004193
4194 def _CheckConfig(seq, expected_data):
4195 """Check the configuration nodes
4196
4197 Args:
4198 seq: Sequence number to check (0 or 1)
4199 expected_data: Expected contents of 'data' property
4200 """
4201 cnode = dtb.GetNode('/configurations')
4202 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004203 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004204
4205 name = 'config-%d' % seq
4206 fnode = dtb.GetNode('/configurations/%s' % name)
4207 self.assertIsNotNone(fnode)
4208 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4209 set(fnode.props.keys()))
4210 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4211 fnode.props['description'].value)
4212 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4213
4214 entry_args = {
4215 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004216 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004217 }
4218 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004219 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004220 entry_args=entry_args,
4221 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4222 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4223 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4224
4225 dtb = fdt.Fdt.FromData(fit_data)
4226 dtb.Scan()
4227 fnode = dtb.GetNode('/images/kernel')
4228 self.assertIn('data', fnode.props)
4229
4230 # Check all the properties in fdt-1 and fdt-2
4231 _CheckFdt(1, TEST_FDT1_DATA)
4232 _CheckFdt(2, TEST_FDT2_DATA)
4233
4234 # Check configurations
4235 _CheckConfig(1, TEST_FDT1_DATA)
4236 _CheckConfig(2, TEST_FDT2_DATA)
4237
4238 def testFitFdtMissingList(self):
4239 """Test handling of a missing 'of-list' entry arg"""
4240 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004241 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004242 self.assertIn("Generator node requires 'of-list' entry argument",
4243 str(e.exception))
4244
4245 def testFitFdtEmptyList(self):
4246 """Test handling of an empty 'of-list' entry arg"""
4247 entry_args = {
4248 'of-list': '',
4249 }
4250 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4251
4252 def testFitFdtMissingProp(self):
4253 """Test handling of a missing 'fit,fdt-list' property"""
4254 with self.assertRaises(ValueError) as e:
4255 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4256 self.assertIn("Generator node requires 'fit,fdt-list' property",
4257 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004258
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004259 def testFitFdtMissing(self):
4260 """Test handling of a missing 'default-dt' entry arg"""
4261 entry_args = {
4262 'of-list': 'test-fdt1 test-fdt2',
4263 }
4264 with self.assertRaises(ValueError) as e:
4265 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004266 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004267 entry_args=entry_args,
4268 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4269 self.assertIn("Generated 'default' node requires default-dt entry argument",
4270 str(e.exception))
4271
4272 def testFitFdtNotInList(self):
4273 """Test handling of a default-dt that is not in the of-list"""
4274 entry_args = {
4275 'of-list': 'test-fdt1 test-fdt2',
4276 'default-dt': 'test-fdt3',
4277 }
4278 with self.assertRaises(ValueError) as e:
4279 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004280 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004281 entry_args=entry_args,
4282 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4283 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4284 str(e.exception))
4285
Simon Glassb2381432020-09-06 10:39:09 -06004286 def testFitExtblobMissingHelp(self):
4287 """Test display of help messages when an external blob is missing"""
4288 control.missing_blob_help = control._ReadMissingBlobHelp()
4289 control.missing_blob_help['wibble'] = 'Wibble test'
4290 control.missing_blob_help['another'] = 'Another test'
4291 with test_util.capture_sys_output() as (stdout, stderr):
4292 self._DoTestFile('168_fit_missing_blob.dts',
4293 allow_missing=True)
4294 err = stderr.getvalue()
4295
4296 # We can get the tag from the name, the type or the missing-msg
4297 # property. Check all three.
4298 self.assertIn('You may need to build ARM Trusted', err)
4299 self.assertIn('Wibble test', err)
4300 self.assertIn('Another test', err)
4301
Simon Glass204aa782020-09-06 10:35:32 -06004302 def testMissingBlob(self):
4303 """Test handling of a blob containing a missing file"""
4304 with self.assertRaises(ValueError) as e:
4305 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4306 self.assertIn("Filename 'missing' not found in input path",
4307 str(e.exception))
4308
Simon Glassfb91d562020-09-06 10:35:33 -06004309 def testEnvironment(self):
4310 """Test adding a U-Boot environment"""
4311 data = self._DoReadFile('174_env.dts')
4312 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4313 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4314 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4315 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4316 env)
4317
4318 def testEnvironmentNoSize(self):
4319 """Test that a missing 'size' property is detected"""
4320 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004321 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004322 self.assertIn("'u-boot-env' entry must have a size property",
4323 str(e.exception))
4324
4325 def testEnvironmentTooSmall(self):
4326 """Test handling of an environment that does not fit"""
4327 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004328 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004329
4330 # checksum, start byte, environment with \0 terminator, final \0
4331 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4332 short = need - 0x8
4333 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4334 str(e.exception))
4335
Simon Glassf2c0dd82020-10-26 17:40:01 -06004336 def testSkipAtStart(self):
4337 """Test handling of skip-at-start section"""
4338 data = self._DoReadFile('177_skip_at_start.dts')
4339 self.assertEqual(U_BOOT_DATA, data)
4340
4341 image = control.images['image']
4342 entries = image.GetEntries()
4343 section = entries['section']
4344 self.assertEqual(0, section.offset)
4345 self.assertEqual(len(U_BOOT_DATA), section.size)
4346 self.assertEqual(U_BOOT_DATA, section.GetData())
4347
4348 entry = section.GetEntries()['u-boot']
4349 self.assertEqual(16, entry.offset)
4350 self.assertEqual(len(U_BOOT_DATA), entry.size)
4351 self.assertEqual(U_BOOT_DATA, entry.data)
4352
4353 def testSkipAtStartPad(self):
4354 """Test handling of skip-at-start section with padded entry"""
4355 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004356 before = tools.get_bytes(0, 8)
4357 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004358 all = before + U_BOOT_DATA + after
4359 self.assertEqual(all, data)
4360
4361 image = control.images['image']
4362 entries = image.GetEntries()
4363 section = entries['section']
4364 self.assertEqual(0, section.offset)
4365 self.assertEqual(len(all), section.size)
4366 self.assertEqual(all, section.GetData())
4367
4368 entry = section.GetEntries()['u-boot']
4369 self.assertEqual(16, entry.offset)
4370 self.assertEqual(len(all), entry.size)
4371 self.assertEqual(U_BOOT_DATA, entry.data)
4372
4373 def testSkipAtStartSectionPad(self):
4374 """Test handling of skip-at-start section with padding"""
4375 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004376 before = tools.get_bytes(0, 8)
4377 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004378 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004379 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004380
4381 image = control.images['image']
4382 entries = image.GetEntries()
4383 section = entries['section']
4384 self.assertEqual(0, section.offset)
4385 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004386 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004387 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004388
4389 entry = section.GetEntries()['u-boot']
4390 self.assertEqual(16, entry.offset)
4391 self.assertEqual(len(U_BOOT_DATA), entry.size)
4392 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004393
Simon Glass7d398bb2020-10-26 17:40:14 -06004394 def testSectionPad(self):
4395 """Testing padding with sections"""
4396 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004397 expected = (tools.get_bytes(ord('&'), 3) +
4398 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004399 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004400 tools.get_bytes(ord('!'), 1) +
4401 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004402 self.assertEqual(expected, data)
4403
4404 def testSectionAlign(self):
4405 """Testing alignment with sections"""
4406 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4407 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004408 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004409 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004410 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004411 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004412 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4413 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004414 self.assertEqual(expected, data)
4415
Simon Glass8f5ef892020-10-26 17:40:25 -06004416 def testCompressImage(self):
4417 """Test compression of the entire image"""
4418 self._CheckLz4()
4419 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4420 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4421 dtb = fdt.Fdt(out_dtb_fname)
4422 dtb.Scan()
4423 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4424 'uncomp-size'])
4425 orig = self._decompress(data)
4426 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4427
4428 # Do a sanity check on various fields
4429 image = control.images['image']
4430 entries = image.GetEntries()
4431 self.assertEqual(2, len(entries))
4432
4433 entry = entries['blob']
4434 self.assertEqual(COMPRESS_DATA, entry.data)
4435 self.assertEqual(len(COMPRESS_DATA), entry.size)
4436
4437 entry = entries['u-boot']
4438 self.assertEqual(U_BOOT_DATA, entry.data)
4439 self.assertEqual(len(U_BOOT_DATA), entry.size)
4440
4441 self.assertEqual(len(data), image.size)
4442 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4443 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4444 orig = self._decompress(image.data)
4445 self.assertEqual(orig, image.uncomp_data)
4446
4447 expected = {
4448 'blob:offset': 0,
4449 'blob:size': len(COMPRESS_DATA),
4450 'u-boot:offset': len(COMPRESS_DATA),
4451 'u-boot:size': len(U_BOOT_DATA),
4452 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4453 'offset': 0,
4454 'image-pos': 0,
4455 'size': len(data),
4456 }
4457 self.assertEqual(expected, props)
4458
4459 def testCompressImageLess(self):
4460 """Test compression where compression reduces the image size"""
4461 self._CheckLz4()
4462 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4463 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4464 dtb = fdt.Fdt(out_dtb_fname)
4465 dtb.Scan()
4466 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4467 'uncomp-size'])
4468 orig = self._decompress(data)
4469
4470 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4471
4472 # Do a sanity check on various fields
4473 image = control.images['image']
4474 entries = image.GetEntries()
4475 self.assertEqual(2, len(entries))
4476
4477 entry = entries['blob']
4478 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4479 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4480
4481 entry = entries['u-boot']
4482 self.assertEqual(U_BOOT_DATA, entry.data)
4483 self.assertEqual(len(U_BOOT_DATA), entry.size)
4484
4485 self.assertEqual(len(data), image.size)
4486 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4487 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4488 image.uncomp_size)
4489 orig = self._decompress(image.data)
4490 self.assertEqual(orig, image.uncomp_data)
4491
4492 expected = {
4493 'blob:offset': 0,
4494 'blob:size': len(COMPRESS_DATA_BIG),
4495 'u-boot:offset': len(COMPRESS_DATA_BIG),
4496 'u-boot:size': len(U_BOOT_DATA),
4497 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4498 'offset': 0,
4499 'image-pos': 0,
4500 'size': len(data),
4501 }
4502 self.assertEqual(expected, props)
4503
4504 def testCompressSectionSize(self):
4505 """Test compression of a section with a fixed size"""
4506 self._CheckLz4()
4507 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4508 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4509 dtb = fdt.Fdt(out_dtb_fname)
4510 dtb.Scan()
4511 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4512 'uncomp-size'])
4513 orig = self._decompress(data)
4514 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4515 expected = {
4516 'section/blob:offset': 0,
4517 'section/blob:size': len(COMPRESS_DATA),
4518 'section/u-boot:offset': len(COMPRESS_DATA),
4519 'section/u-boot:size': len(U_BOOT_DATA),
4520 'section:offset': 0,
4521 'section:image-pos': 0,
4522 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4523 'section:size': 0x30,
4524 'offset': 0,
4525 'image-pos': 0,
4526 'size': 0x30,
4527 }
4528 self.assertEqual(expected, props)
4529
4530 def testCompressSection(self):
4531 """Test compression of a section with no fixed size"""
4532 self._CheckLz4()
4533 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4534 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4535 dtb = fdt.Fdt(out_dtb_fname)
4536 dtb.Scan()
4537 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4538 'uncomp-size'])
4539 orig = self._decompress(data)
4540 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4541 expected = {
4542 'section/blob:offset': 0,
4543 'section/blob:size': len(COMPRESS_DATA),
4544 'section/u-boot:offset': len(COMPRESS_DATA),
4545 'section/u-boot:size': len(U_BOOT_DATA),
4546 'section:offset': 0,
4547 'section:image-pos': 0,
4548 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4549 'section:size': len(data),
4550 'offset': 0,
4551 'image-pos': 0,
4552 'size': len(data),
4553 }
4554 self.assertEqual(expected, props)
4555
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004556 def testLz4Missing(self):
4557 """Test that binman still produces an image if lz4 is missing"""
4558 with test_util.capture_sys_output() as (_, stderr):
4559 self._DoTestFile('185_compress_section.dts',
4560 force_missing_bintools='lz4')
4561 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004562 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004563
Simon Glass8f5ef892020-10-26 17:40:25 -06004564 def testCompressExtra(self):
4565 """Test compression of a section with no fixed size"""
4566 self._CheckLz4()
4567 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4568 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4569 dtb = fdt.Fdt(out_dtb_fname)
4570 dtb.Scan()
4571 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4572 'uncomp-size'])
4573
4574 base = data[len(U_BOOT_DATA):]
4575 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4576 rest = base[len(U_BOOT_DATA):]
4577
4578 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004579 bintool = self.comp_bintools['lz4']
4580 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004581 data1 = rest[:len(expect1)]
4582 section1 = self._decompress(data1)
4583 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004584 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4585 rest1 = rest[len(expect1):]
4586
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004587 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004588 data2 = rest1[:len(expect2)]
4589 section2 = self._decompress(data2)
4590 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004591 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4592 rest2 = rest1[len(expect2):]
4593
4594 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4595 len(expect2) + len(U_BOOT_DATA))
4596 #self.assertEquals(expect_size, len(data))
4597
4598 #self.assertEquals(U_BOOT_DATA, rest2)
4599
4600 self.maxDiff = None
4601 expected = {
4602 'u-boot:offset': 0,
4603 'u-boot:image-pos': 0,
4604 'u-boot:size': len(U_BOOT_DATA),
4605
4606 'base:offset': len(U_BOOT_DATA),
4607 'base:image-pos': len(U_BOOT_DATA),
4608 'base:size': len(data) - len(U_BOOT_DATA),
4609 'base/u-boot:offset': 0,
4610 'base/u-boot:image-pos': len(U_BOOT_DATA),
4611 'base/u-boot:size': len(U_BOOT_DATA),
4612 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4613 len(expect2),
4614 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4615 len(expect2),
4616 'base/u-boot2:size': len(U_BOOT_DATA),
4617
4618 'base/section:offset': len(U_BOOT_DATA),
4619 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4620 'base/section:size': len(expect1),
4621 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4622 'base/section/blob:offset': 0,
4623 'base/section/blob:size': len(COMPRESS_DATA),
4624 'base/section/u-boot:offset': len(COMPRESS_DATA),
4625 'base/section/u-boot:size': len(U_BOOT_DATA),
4626
4627 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4628 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4629 'base/section2:size': len(expect2),
4630 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4631 'base/section2/blob:offset': 0,
4632 'base/section2/blob:size': len(COMPRESS_DATA),
4633 'base/section2/blob2:offset': len(COMPRESS_DATA),
4634 'base/section2/blob2:size': len(COMPRESS_DATA),
4635
4636 'offset': 0,
4637 'image-pos': 0,
4638 'size': len(data),
4639 }
4640 self.assertEqual(expected, props)
4641
Simon Glass870a9ea2021-01-06 21:35:15 -07004642 def testSymbolsSubsection(self):
4643 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004644 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004645
Simon Glass939d1062021-01-06 21:35:16 -07004646 def testReadImageEntryArg(self):
4647 """Test reading an image that would need an entry arg to generate"""
4648 entry_args = {
4649 'cros-ec-rw-path': 'ecrw.bin',
4650 }
4651 data = self.data = self._DoReadFileDtb(
4652 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4653 entry_args=entry_args)
4654
Simon Glassc1aa66e2022-01-29 14:14:04 -07004655 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004656 orig_image = control.images['image']
4657
4658 # This should not generate an error about the missing 'cros-ec-rw-path'
4659 # since we are reading the image from a file. Compare with
4660 # testEntryArgsRequired()
4661 image = Image.FromFile(image_fname)
4662 self.assertEqual(orig_image.GetEntries().keys(),
4663 image.GetEntries().keys())
4664
Simon Glass6eb99322021-01-06 21:35:18 -07004665 def testFilesAlign(self):
4666 """Test alignment with files"""
4667 data = self._DoReadFile('190_files_align.dts')
4668
4669 # The first string is 15 bytes so will align to 16
4670 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4671 self.assertEqual(expect, data)
4672
Simon Glass5c6ba712021-01-06 21:35:19 -07004673 def testReadImageSkip(self):
4674 """Test reading an image and accessing its FDT map"""
4675 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004676 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004677 orig_image = control.images['image']
4678 image = Image.FromFile(image_fname)
4679 self.assertEqual(orig_image.GetEntries().keys(),
4680 image.GetEntries().keys())
4681
4682 orig_entry = orig_image.GetEntries()['fdtmap']
4683 entry = image.GetEntries()['fdtmap']
4684 self.assertEqual(orig_entry.offset, entry.offset)
4685 self.assertEqual(orig_entry.size, entry.size)
4686 self.assertEqual(16, entry.image_pos)
4687
4688 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4689
4690 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4691
Simon Glass77a64e02021-03-18 20:24:57 +13004692 def testTplNoDtb(self):
4693 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004694 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004695 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4696 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4697 data[:len(U_BOOT_TPL_NODTB_DATA)])
4698
Simon Glassd26efc82021-03-18 20:24:58 +13004699 def testTplBssPad(self):
4700 """Test that we can pad TPL's BSS with zeros"""
4701 # ELF file with a '__bss_size' symbol
4702 self._SetupTplElf()
4703 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004704 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004705 data)
4706
4707 def testTplBssPadMissing(self):
4708 """Test that a missing symbol is detected"""
4709 self._SetupTplElf('u_boot_ucode_ptr')
4710 with self.assertRaises(ValueError) as e:
4711 self._DoReadFile('193_tpl_bss_pad.dts')
4712 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4713 str(e.exception))
4714
Simon Glass06684922021-03-18 20:25:07 +13004715 def checkDtbSizes(self, data, pad_len, start):
4716 """Check the size arguments in a dtb embedded in an image
4717
4718 Args:
4719 data: The image data
4720 pad_len: Length of the pad section in the image, in bytes
4721 start: Start offset of the devicetree to examine, within the image
4722
4723 Returns:
4724 Size of the devicetree in bytes
4725 """
4726 dtb_data = data[start:]
4727 dtb = fdt.Fdt.FromData(dtb_data)
4728 fdt_size = dtb.GetFdtObj().totalsize()
4729 dtb.Scan()
4730 props = self._GetPropTree(dtb, 'size')
4731 self.assertEqual({
4732 'size': len(data),
4733 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4734 'u-boot-spl/u-boot-spl-dtb:size': 801,
4735 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4736 'u-boot-spl:size': 860,
4737 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4738 'u-boot/u-boot-dtb:size': 781,
4739 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4740 'u-boot:size': 827,
4741 }, props)
4742 return fdt_size
4743
4744 def testExpanded(self):
4745 """Test that an expanded entry type is selected when needed"""
4746 self._SetupSplElf()
4747 self._SetupTplElf()
4748
4749 # SPL has a devicetree, TPL does not
4750 entry_args = {
4751 'spl-dtb': '1',
4752 'spl-bss-pad': 'y',
4753 'tpl-dtb': '',
4754 }
4755 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4756 entry_args=entry_args)
4757 image = control.images['image']
4758 entries = image.GetEntries()
4759 self.assertEqual(3, len(entries))
4760
4761 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4762 self.assertIn('u-boot', entries)
4763 entry = entries['u-boot']
4764 self.assertEqual('u-boot-expanded', entry.etype)
4765 subent = entry.GetEntries()
4766 self.assertEqual(2, len(subent))
4767 self.assertIn('u-boot-nodtb', subent)
4768 self.assertIn('u-boot-dtb', subent)
4769
4770 # Second, u-boot-spl, which should be expanded into three parts
4771 self.assertIn('u-boot-spl', entries)
4772 entry = entries['u-boot-spl']
4773 self.assertEqual('u-boot-spl-expanded', entry.etype)
4774 subent = entry.GetEntries()
4775 self.assertEqual(3, len(subent))
4776 self.assertIn('u-boot-spl-nodtb', subent)
4777 self.assertIn('u-boot-spl-bss-pad', subent)
4778 self.assertIn('u-boot-spl-dtb', subent)
4779
4780 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4781 # devicetree
4782 self.assertIn('u-boot-tpl', entries)
4783 entry = entries['u-boot-tpl']
4784 self.assertEqual('u-boot-tpl', entry.etype)
4785 self.assertEqual(None, entry.GetEntries())
4786
4787 def testExpandedTpl(self):
4788 """Test that an expanded entry type is selected for TPL when needed"""
4789 self._SetupTplElf()
4790
4791 entry_args = {
4792 'tpl-bss-pad': 'y',
4793 'tpl-dtb': 'y',
4794 }
4795 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4796 entry_args=entry_args)
4797 image = control.images['image']
4798 entries = image.GetEntries()
4799 self.assertEqual(1, len(entries))
4800
4801 # We only have u-boot-tpl, which be expanded
4802 self.assertIn('u-boot-tpl', entries)
4803 entry = entries['u-boot-tpl']
4804 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4805 subent = entry.GetEntries()
4806 self.assertEqual(3, len(subent))
4807 self.assertIn('u-boot-tpl-nodtb', subent)
4808 self.assertIn('u-boot-tpl-bss-pad', subent)
4809 self.assertIn('u-boot-tpl-dtb', subent)
4810
4811 def testExpandedNoPad(self):
4812 """Test an expanded entry without BSS pad enabled"""
4813 self._SetupSplElf()
4814 self._SetupTplElf()
4815
4816 # SPL has a devicetree, TPL does not
4817 entry_args = {
4818 'spl-dtb': 'something',
4819 'spl-bss-pad': 'n',
4820 'tpl-dtb': '',
4821 }
4822 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4823 entry_args=entry_args)
4824 image = control.images['image']
4825 entries = image.GetEntries()
4826
4827 # Just check u-boot-spl, which should be expanded into two parts
4828 self.assertIn('u-boot-spl', entries)
4829 entry = entries['u-boot-spl']
4830 self.assertEqual('u-boot-spl-expanded', entry.etype)
4831 subent = entry.GetEntries()
4832 self.assertEqual(2, len(subent))
4833 self.assertIn('u-boot-spl-nodtb', subent)
4834 self.assertIn('u-boot-spl-dtb', subent)
4835
4836 def testExpandedTplNoPad(self):
4837 """Test that an expanded entry type with padding disabled in TPL"""
4838 self._SetupTplElf()
4839
4840 entry_args = {
4841 'tpl-bss-pad': '',
4842 'tpl-dtb': 'y',
4843 }
4844 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4845 entry_args=entry_args)
4846 image = control.images['image']
4847 entries = image.GetEntries()
4848 self.assertEqual(1, len(entries))
4849
4850 # We only have u-boot-tpl, which be expanded
4851 self.assertIn('u-boot-tpl', entries)
4852 entry = entries['u-boot-tpl']
4853 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4854 subent = entry.GetEntries()
4855 self.assertEqual(2, len(subent))
4856 self.assertIn('u-boot-tpl-nodtb', subent)
4857 self.assertIn('u-boot-tpl-dtb', subent)
4858
4859 def testFdtInclude(self):
4860 """Test that an Fdt is update within all binaries"""
4861 self._SetupSplElf()
4862 self._SetupTplElf()
4863
4864 # SPL has a devicetree, TPL does not
4865 self.maxDiff = None
4866 entry_args = {
4867 'spl-dtb': '1',
4868 'spl-bss-pad': 'y',
4869 'tpl-dtb': '',
4870 }
4871 # Build the image. It includes two separate devicetree binaries, each
4872 # with their own contents, but all contain the binman definition.
4873 data = self._DoReadFileDtb(
4874 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4875 update_dtb=True, entry_args=entry_args)[0]
4876 pad_len = 10
4877
4878 # Check the U-Boot dtb
4879 start = len(U_BOOT_NODTB_DATA)
4880 fdt_size = self.checkDtbSizes(data, pad_len, start)
4881
4882 # Now check SPL
4883 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4884 fdt_size = self.checkDtbSizes(data, pad_len, start)
4885
4886 # TPL has no devicetree
4887 start += fdt_size + len(U_BOOT_TPL_DATA)
4888 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004889
Simon Glass3d433382021-03-21 18:24:30 +13004890 def testSymbolsExpanded(self):
4891 """Test binman can assign symbols in expanded entries"""
4892 entry_args = {
4893 'spl-dtb': '1',
4894 }
4895 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4896 U_BOOT_SPL_DTB_DATA, 0x38,
4897 entry_args=entry_args, use_expanded=True)
4898
Simon Glass189f2912021-03-21 18:24:31 +13004899 def testCollection(self):
4900 """Test a collection"""
4901 data = self._DoReadFile('198_collection.dts')
4902 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004903 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4904 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004905 data)
4906
Simon Glass631f7522021-03-21 18:24:32 +13004907 def testCollectionSection(self):
4908 """Test a collection where a section must be built first"""
4909 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004910 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004911 # building the contents, producing an error is anything is still
4912 # missing.
4913 data = self._DoReadFile('199_collection_section.dts')
4914 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004915 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4916 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004917 data)
4918
Simon Glass5ff9fed2021-03-21 18:24:33 +13004919 def testAlignDefault(self):
4920 """Test that default alignment works on sections"""
4921 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004922 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004923 U_BOOT_DATA)
4924 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004925 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004926 # No alignment within the nested section
4927 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4928 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004929 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004930 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004931
Bin Meng4c4d6072021-05-10 20:23:33 +08004932 def testPackOpenSBI(self):
4933 """Test that an image with an OpenSBI binary can be created"""
4934 data = self._DoReadFile('201_opensbi.dts')
4935 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4936
Simon Glassc69d19c2021-07-06 10:36:37 -06004937 def testSectionsSingleThread(self):
4938 """Test sections without multithreading"""
4939 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004940 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4941 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4942 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004943 self.assertEqual(expected, data)
4944
4945 def testThreadTimeout(self):
4946 """Test handling a thread that takes too long"""
4947 with self.assertRaises(ValueError) as e:
4948 self._DoTestFile('202_section_timeout.dts',
4949 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004950 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004951
Simon Glass03ebc202021-07-06 10:36:41 -06004952 def testTiming(self):
4953 """Test output of timing information"""
4954 data = self._DoReadFile('055_sections.dts')
4955 with test_util.capture_sys_output() as (stdout, stderr):
4956 state.TimingShow()
4957 self.assertIn('read:', stdout.getvalue())
4958 self.assertIn('compress:', stdout.getvalue())
4959
Simon Glass0427bed2021-11-03 21:09:18 -06004960 def testUpdateFdtInElf(self):
4961 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004962 if not elf.ELF_TOOLS:
4963 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004964 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4965 outfile = os.path.join(self._indir, 'u-boot.out')
4966 begin_sym = 'dtb_embed_begin'
4967 end_sym = 'dtb_embed_end'
4968 retcode = self._DoTestFile(
4969 '060_fdt_update.dts', update_dtb=True,
4970 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4971 self.assertEqual(0, retcode)
4972
4973 # Check that the output file does in fact contact a dtb with the binman
4974 # definition in the correct place
4975 syms = elf.GetSymbolFileOffset(infile,
4976 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004977 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004978 dtb_data = data[syms['dtb_embed_begin'].offset:
4979 syms['dtb_embed_end'].offset]
4980
4981 dtb = fdt.Fdt.FromData(dtb_data)
4982 dtb.Scan()
4983 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4984 self.assertEqual({
4985 'image-pos': 0,
4986 'offset': 0,
4987 '_testing:offset': 32,
4988 '_testing:size': 2,
4989 '_testing:image-pos': 32,
4990 'section@0/u-boot:offset': 0,
4991 'section@0/u-boot:size': len(U_BOOT_DATA),
4992 'section@0/u-boot:image-pos': 0,
4993 'section@0:offset': 0,
4994 'section@0:size': 16,
4995 'section@0:image-pos': 0,
4996
4997 'section@1/u-boot:offset': 0,
4998 'section@1/u-boot:size': len(U_BOOT_DATA),
4999 'section@1/u-boot:image-pos': 16,
5000 'section@1:offset': 16,
5001 'section@1:size': 16,
5002 'section@1:image-pos': 16,
5003 'size': 40
5004 }, props)
5005
5006 def testUpdateFdtInElfInvalid(self):
5007 """Test that invalid args are detected with --update-fdt-in-elf"""
5008 with self.assertRaises(ValueError) as e:
5009 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5010 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5011 str(e.exception))
5012
5013 def testUpdateFdtInElfNoSyms(self):
5014 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005015 if not elf.ELF_TOOLS:
5016 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005017 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5018 outfile = ''
5019 begin_sym = 'wrong_begin'
5020 end_sym = 'wrong_end'
5021 with self.assertRaises(ValueError) as e:
5022 self._DoTestFile(
5023 '060_fdt_update.dts',
5024 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5025 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5026 str(e.exception))
5027
5028 def testUpdateFdtInElfTooSmall(self):
5029 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005030 if not elf.ELF_TOOLS:
5031 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005032 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5033 outfile = os.path.join(self._indir, 'u-boot.out')
5034 begin_sym = 'dtb_embed_begin'
5035 end_sym = 'dtb_embed_end'
5036 with self.assertRaises(ValueError) as e:
5037 self._DoTestFile(
5038 '060_fdt_update.dts', update_dtb=True,
5039 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5040 self.assertRegex(
5041 str(e.exception),
5042 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5043
Simon Glassc475dec2021-11-23 11:03:42 -07005044 def testVersion(self):
5045 """Test we can get the binman version"""
5046 version = '(unreleased)'
5047 self.assertEqual(version, state.GetVersion(self._indir))
5048
5049 with self.assertRaises(SystemExit):
5050 with test_util.capture_sys_output() as (_, stderr):
5051 self._DoBinman('-V')
5052 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5053
5054 # Try running the tool too, just to be safe
5055 result = self._RunBinman('-V')
5056 self.assertEqual('Binman %s\n' % version, result.stderr)
5057
5058 # Set up a version file to make sure that works
5059 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07005060 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07005061 binary=False)
5062 self.assertEqual(version, state.GetVersion(self._indir))
5063
Simon Glass943bf782021-11-23 21:09:50 -07005064 def testAltFormat(self):
5065 """Test that alternative formats can be used to extract"""
5066 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5067
5068 try:
5069 tmpdir, updated_fname = self._SetupImageInTmpdir()
5070 with test_util.capture_sys_output() as (stdout, _):
5071 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5072 self.assertEqual(
5073 '''Flag (-F) Entry type Description
5074fdt fdtmap Extract the devicetree blob from the fdtmap
5075''',
5076 stdout.getvalue())
5077
5078 dtb = os.path.join(tmpdir, 'fdt.dtb')
5079 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5080 dtb, 'fdtmap')
5081
5082 # Check that we can read it and it can be scanning, meaning it does
5083 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005084 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005085 dtb = fdt.Fdt.FromData(data)
5086 dtb.Scan()
5087
5088 # Now check u-boot which has no alt_format
5089 fname = os.path.join(tmpdir, 'fdt.dtb')
5090 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5091 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005092 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005093 self.assertEqual(U_BOOT_DATA, data)
5094
5095 finally:
5096 shutil.rmtree(tmpdir)
5097
Simon Glasscc2c5002021-11-23 21:09:52 -07005098 def testExtblobList(self):
5099 """Test an image with an external blob list"""
5100 data = self._DoReadFile('215_blob_ext_list.dts')
5101 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5102
5103 def testExtblobListMissing(self):
5104 """Test an image with a missing external blob"""
5105 with self.assertRaises(ValueError) as e:
5106 self._DoReadFile('216_blob_ext_list_missing.dts')
5107 self.assertIn("Filename 'missing-file' not found in input path",
5108 str(e.exception))
5109
5110 def testExtblobListMissingOk(self):
5111 """Test an image with an missing external blob that is allowed"""
5112 with test_util.capture_sys_output() as (stdout, stderr):
5113 self._DoTestFile('216_blob_ext_list_missing.dts',
5114 allow_missing=True)
5115 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005116 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005117
Simon Glass75989722021-11-23 21:08:59 -07005118 def testFip(self):
5119 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5120 data = self._DoReadFile('203_fip.dts')
5121 hdr, fents = fip_util.decode_fip(data)
5122 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5123 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5124 self.assertEqual(0x123, hdr.flags)
5125
5126 self.assertEqual(2, len(fents))
5127
5128 fent = fents[0]
5129 self.assertEqual(
5130 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5131 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5132 self.assertEqual('soc-fw', fent.fip_type)
5133 self.assertEqual(0x88, fent.offset)
5134 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5135 self.assertEqual(0x123456789abcdef, fent.flags)
5136 self.assertEqual(ATF_BL31_DATA, fent.data)
5137 self.assertEqual(True, fent.valid)
5138
5139 fent = fents[1]
5140 self.assertEqual(
5141 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5142 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5143 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5144 self.assertEqual(0x8c, fent.offset)
5145 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5146 self.assertEqual(0, fent.flags)
5147 self.assertEqual(ATF_BL2U_DATA, fent.data)
5148 self.assertEqual(True, fent.valid)
5149
5150 def testFipOther(self):
5151 """Basic FIP with something that isn't a external blob"""
5152 data = self._DoReadFile('204_fip_other.dts')
5153 hdr, fents = fip_util.decode_fip(data)
5154
5155 self.assertEqual(2, len(fents))
5156 fent = fents[1]
5157 self.assertEqual('rot-cert', fent.fip_type)
5158 self.assertEqual(b'aa', fent.data)
5159
Simon Glass75989722021-11-23 21:08:59 -07005160 def testFipNoType(self):
5161 """FIP with an entry of an unknown type"""
5162 with self.assertRaises(ValueError) as e:
5163 self._DoReadFile('205_fip_no_type.dts')
5164 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5165 str(e.exception))
5166
5167 def testFipUuid(self):
5168 """Basic FIP with a manual uuid"""
5169 data = self._DoReadFile('206_fip_uuid.dts')
5170 hdr, fents = fip_util.decode_fip(data)
5171
5172 self.assertEqual(2, len(fents))
5173 fent = fents[1]
5174 self.assertEqual(None, fent.fip_type)
5175 self.assertEqual(
5176 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5177 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5178 fent.uuid)
5179 self.assertEqual(U_BOOT_DATA, fent.data)
5180
5181 def testFipLs(self):
5182 """Test listing a FIP"""
5183 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5184 hdr, fents = fip_util.decode_fip(data)
5185
5186 try:
5187 tmpdir, updated_fname = self._SetupImageInTmpdir()
5188 with test_util.capture_sys_output() as (stdout, stderr):
5189 self._DoBinman('ls', '-i', updated_fname)
5190 finally:
5191 shutil.rmtree(tmpdir)
5192 lines = stdout.getvalue().splitlines()
5193 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005194'Name Image-pos Size Entry-type Offset Uncomp-size',
5195'--------------------------------------------------------------',
5196'image 0 2d3 section 0',
5197' atf-fip 0 90 atf-fip 0',
5198' soc-fw 88 4 blob-ext 88',
5199' u-boot 8c 4 u-boot 8c',
5200' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005201]
5202 self.assertEqual(expected, lines)
5203
5204 image = control.images['image']
5205 entries = image.GetEntries()
5206 fdtmap = entries['fdtmap']
5207
5208 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5209 magic = fdtmap_data[:8]
5210 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005211 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005212
5213 fdt_data = fdtmap_data[16:]
5214 dtb = fdt.Fdt.FromData(fdt_data)
5215 dtb.Scan()
5216 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5217 self.assertEqual({
5218 'atf-fip/soc-fw:image-pos': 136,
5219 'atf-fip/soc-fw:offset': 136,
5220 'atf-fip/soc-fw:size': 4,
5221 'atf-fip/u-boot:image-pos': 140,
5222 'atf-fip/u-boot:offset': 140,
5223 'atf-fip/u-boot:size': 4,
5224 'atf-fip:image-pos': 0,
5225 'atf-fip:offset': 0,
5226 'atf-fip:size': 144,
5227 'image-pos': 0,
5228 'offset': 0,
5229 'fdtmap:image-pos': fdtmap.image_pos,
5230 'fdtmap:offset': fdtmap.offset,
5231 'fdtmap:size': len(fdtmap_data),
5232 'size': len(data),
5233 }, props)
5234
5235 def testFipExtractOneEntry(self):
5236 """Test extracting a single entry fron an FIP"""
5237 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005238 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005239 fname = os.path.join(self._indir, 'output.extact')
5240 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005241 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005242 self.assertEqual(U_BOOT_DATA, data)
5243
5244 def testFipReplace(self):
5245 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005246 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005247 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005248 updated_fname = tools.get_output_filename('image-updated.bin')
5249 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005250 entry_name = 'atf-fip/u-boot'
5251 control.WriteEntry(updated_fname, entry_name, expected,
5252 allow_resize=True)
5253 actual = control.ReadEntry(updated_fname, entry_name)
5254 self.assertEqual(expected, actual)
5255
Simon Glassc1aa66e2022-01-29 14:14:04 -07005256 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005257 hdr, fents = fip_util.decode_fip(new_data)
5258
5259 self.assertEqual(2, len(fents))
5260
5261 # Check that the FIP entry is updated
5262 fent = fents[1]
5263 self.assertEqual(0x8c, fent.offset)
5264 self.assertEqual(len(expected), fent.size)
5265 self.assertEqual(0, fent.flags)
5266 self.assertEqual(expected, fent.data)
5267 self.assertEqual(True, fent.valid)
5268
5269 def testFipMissing(self):
5270 with test_util.capture_sys_output() as (stdout, stderr):
5271 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5272 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005273 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005274
5275 def testFipSize(self):
5276 """Test a FIP with a size property"""
5277 data = self._DoReadFile('210_fip_size.dts')
5278 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5279 hdr, fents = fip_util.decode_fip(data)
5280 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5281 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5282
5283 self.assertEqual(1, len(fents))
5284
5285 fent = fents[0]
5286 self.assertEqual('soc-fw', fent.fip_type)
5287 self.assertEqual(0x60, fent.offset)
5288 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5289 self.assertEqual(ATF_BL31_DATA, fent.data)
5290 self.assertEqual(True, fent.valid)
5291
5292 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005293 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005294
5295 def testFipBadAlign(self):
5296 """Test that an invalid alignment value in a FIP is detected"""
5297 with self.assertRaises(ValueError) as e:
5298 self._DoTestFile('211_fip_bad_align.dts')
5299 self.assertIn(
5300 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5301 str(e.exception))
5302
5303 def testFipCollection(self):
5304 """Test using a FIP in a collection"""
5305 data = self._DoReadFile('212_fip_collection.dts')
5306 entry1 = control.images['image'].GetEntries()['collection']
5307 data1 = data[:entry1.size]
5308 hdr1, fents2 = fip_util.decode_fip(data1)
5309
5310 entry2 = control.images['image'].GetEntries()['atf-fip']
5311 data2 = data[entry2.offset:entry2.offset + entry2.size]
5312 hdr1, fents2 = fip_util.decode_fip(data2)
5313
5314 # The 'collection' entry should have U-Boot included at the end
5315 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5316 self.assertEqual(data1, data2 + U_BOOT_DATA)
5317 self.assertEqual(U_BOOT_DATA, data1[-4:])
5318
5319 # There should be a U-Boot after the final FIP
5320 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005321
Simon Glass32d4f102022-01-12 13:10:35 -07005322 def testFakeBlob(self):
5323 """Test handling of faking an external blob"""
5324 with test_util.capture_sys_output() as (stdout, stderr):
5325 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5326 allow_fake_blobs=True)
5327 err = stderr.getvalue()
5328 self.assertRegex(
5329 err,
5330 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005331
Simon Glassf4590e02022-01-09 20:13:46 -07005332 def testExtblobListFaked(self):
5333 """Test an extblob with missing external blob that are faked"""
5334 with test_util.capture_sys_output() as (stdout, stderr):
5335 self._DoTestFile('216_blob_ext_list_missing.dts',
5336 allow_fake_blobs=True)
5337 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005338 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005339
Simon Glass56ee85e2022-01-09 20:13:57 -07005340 def testListBintools(self):
5341 args = ['tool', '--list']
5342 with test_util.capture_sys_output() as (stdout, _):
5343 self._DoBinman(*args)
5344 out = stdout.getvalue().splitlines()
5345 self.assertTrue(len(out) >= 2)
5346
5347 def testFetchBintools(self):
5348 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005349 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005350 raise urllib.error.URLError('my error')
5351
5352 args = ['tool']
5353 with self.assertRaises(ValueError) as e:
5354 self._DoBinman(*args)
5355 self.assertIn("Invalid arguments to 'tool' subcommand",
5356 str(e.exception))
5357
5358 args = ['tool', '--fetch']
5359 with self.assertRaises(ValueError) as e:
5360 self._DoBinman(*args)
5361 self.assertIn('Please specify bintools to fetch', str(e.exception))
5362
5363 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005364 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005365 side_effect=fail_download):
5366 with test_util.capture_sys_output() as (stdout, _):
5367 self._DoBinman(*args)
5368 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5369
Simon Glassbc570642022-01-09 20:14:11 -07005370 def testBintoolDocs(self):
5371 """Test for creation of bintool documentation"""
5372 with test_util.capture_sys_output() as (stdout, stderr):
5373 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5374 self.assertTrue(len(stdout.getvalue()) > 0)
5375
5376 def testBintoolDocsMissing(self):
5377 """Test handling of missing bintool documentation"""
5378 with self.assertRaises(ValueError) as e:
5379 with test_util.capture_sys_output() as (stdout, stderr):
5380 control.write_bintool_docs(
5381 control.bintool.Bintool.get_tool_list(), 'mkimage')
5382 self.assertIn('Documentation is missing for modules: mkimage',
5383 str(e.exception))
5384
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005385 def testListWithGenNode(self):
5386 """Check handling of an FDT map when the section cannot be found"""
5387 entry_args = {
5388 'of-list': 'test-fdt1 test-fdt2',
5389 }
5390 data = self._DoReadFileDtb(
5391 '219_fit_gennode.dts',
5392 entry_args=entry_args,
5393 use_real_dtb=True,
5394 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5395
5396 try:
5397 tmpdir, updated_fname = self._SetupImageInTmpdir()
5398 with test_util.capture_sys_output() as (stdout, stderr):
5399 self._RunBinman('ls', '-i', updated_fname)
5400 finally:
5401 shutil.rmtree(tmpdir)
5402
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005403 def testFitSubentryUsesBintool(self):
5404 """Test that binman FIT subentries can use bintools"""
5405 command.test_result = self._HandleGbbCommand
5406 entry_args = {
5407 'keydir': 'devkeys',
5408 'bmpblk': 'bmpblk.bin',
5409 }
5410 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5411 entry_args=entry_args)
5412
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005413 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5414 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005415 self.assertIn(expected, data)
5416
5417 def testFitSubentryMissingBintool(self):
5418 """Test that binman reports missing bintools for FIT subentries"""
5419 entry_args = {
5420 'keydir': 'devkeys',
5421 }
5422 with test_util.capture_sys_output() as (_, stderr):
5423 self._DoTestFile('220_fit_subentry_bintool.dts',
5424 force_missing_bintools='futility', entry_args=entry_args)
5425 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005426 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005427
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005428 def testFitSubentryHashSubnode(self):
5429 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005430 self._SetupSplElf()
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005431 data, _, _, out_dtb_name = self._DoReadFileDtb(
5432 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5433
5434 mkimage_dtb = fdt.Fdt.FromData(data)
5435 mkimage_dtb.Scan()
5436 binman_dtb = fdt.Fdt(out_dtb_name)
5437 binman_dtb.Scan()
5438
5439 # Check that binman didn't add hash values
5440 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5441 self.assertNotIn('value', fnode.props)
5442
5443 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5444 self.assertNotIn('value', fnode.props)
5445
5446 # Check that mkimage added hash values
5447 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5448 self.assertIn('value', fnode.props)
5449
5450 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5451 self.assertIn('value', fnode.props)
5452
Roger Quadros47f420a2022-02-19 20:50:04 +02005453 def testPackTeeOs(self):
5454 """Test that an image with an TEE binary can be created"""
5455 data = self._DoReadFile('222_tee_os.dts')
5456 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5457
Simon Glass6a0b5f82022-02-08 11:50:03 -07005458 def testFitFdtOper(self):
5459 """Check handling of a specified FIT operation"""
5460 entry_args = {
5461 'of-list': 'test-fdt1 test-fdt2',
5462 'default-dt': 'test-fdt2',
5463 }
5464 self._DoReadFileDtb(
5465 '223_fit_fdt_oper.dts',
5466 entry_args=entry_args,
5467 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5468
5469 def testFitFdtBadOper(self):
5470 """Check handling of an FDT map when the section cannot be found"""
5471 with self.assertRaises(ValueError) as exc:
5472 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005473 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005474 str(exc.exception))
5475
Simon Glass80a66ae2022-03-05 20:18:59 -07005476 def test_uses_expand_size(self):
5477 """Test that the 'expand-size' property cannot be used anymore"""
5478 with self.assertRaises(ValueError) as e:
5479 data = self._DoReadFile('225_expand_size_bad.dts')
5480 self.assertIn(
5481 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5482 str(e.exception))
5483
Simon Glass40c8bdd2022-03-05 20:19:12 -07005484 def testFitSplitElf(self):
5485 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005486 if not elf.ELF_TOOLS:
5487 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005488 entry_args = {
5489 'of-list': 'test-fdt1 test-fdt2',
5490 'default-dt': 'test-fdt2',
5491 'atf-bl31-path': 'bl31.elf',
5492 'tee-os-path': 'tee.elf',
5493 }
5494 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5495 data = self._DoReadFileDtb(
5496 '226_fit_split_elf.dts',
5497 entry_args=entry_args,
5498 extra_indirs=[test_subdir])[0]
5499
5500 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5501 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5502
5503 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5504 'data', 'load'}
5505 dtb = fdt.Fdt.FromData(fit_data)
5506 dtb.Scan()
5507
5508 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5509 segments, entry = elf.read_loadable_segments(elf_data)
5510
5511 # We assume there are two segments
5512 self.assertEquals(2, len(segments))
5513
5514 atf1 = dtb.GetNode('/images/atf-1')
5515 _, start, data = segments[0]
5516 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5517 self.assertEqual(entry,
5518 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5519 self.assertEqual(start,
5520 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5521 self.assertEqual(data, atf1.props['data'].bytes)
5522
Jonas Karlman00b3d532023-01-21 19:01:48 +00005523 hash_node = atf1.FindNode('hash')
5524 self.assertIsNotNone(hash_node)
5525 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5526
Simon Glass40c8bdd2022-03-05 20:19:12 -07005527 atf2 = dtb.GetNode('/images/atf-2')
5528 self.assertEqual(base_keys, atf2.props.keys())
5529 _, start, data = segments[1]
5530 self.assertEqual(start,
5531 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5532 self.assertEqual(data, atf2.props['data'].bytes)
5533
Jonas Karlman00b3d532023-01-21 19:01:48 +00005534 hash_node = atf2.FindNode('hash')
5535 self.assertIsNotNone(hash_node)
5536 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5537
5538 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5539 self.assertIsNotNone(hash_node)
5540 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5541
Simon Glass40c8bdd2022-03-05 20:19:12 -07005542 conf = dtb.GetNode('/configurations')
5543 self.assertEqual({'default'}, conf.props.keys())
5544
5545 for subnode in conf.subnodes:
5546 self.assertEqual({'description', 'fdt', 'loadables'},
5547 subnode.props.keys())
5548 self.assertEqual(
5549 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5550 fdt_util.GetStringList(subnode, 'loadables'))
5551
5552 def _check_bad_fit(self, dts):
5553 """Check a bad FIT
5554
5555 This runs with the given dts and returns the assertion raised
5556
5557 Args:
5558 dts (str): dts filename to use
5559
5560 Returns:
5561 str: Assertion string raised
5562 """
5563 entry_args = {
5564 'of-list': 'test-fdt1 test-fdt2',
5565 'default-dt': 'test-fdt2',
5566 'atf-bl31-path': 'bl31.elf',
5567 'tee-os-path': 'tee.elf',
5568 }
5569 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5570 with self.assertRaises(ValueError) as exc:
5571 self._DoReadFileDtb(dts, entry_args=entry_args,
5572 extra_indirs=[test_subdir])[0]
5573 return str(exc.exception)
5574
5575 def testFitSplitElfBadElf(self):
5576 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005577 if not elf.ELF_TOOLS:
5578 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005579 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5580 entry_args = {
5581 'of-list': 'test-fdt1 test-fdt2',
5582 'default-dt': 'test-fdt2',
5583 'atf-bl31-path': 'bad.elf',
5584 'tee-os-path': 'tee.elf',
5585 }
5586 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5587 with self.assertRaises(ValueError) as exc:
5588 self._DoReadFileDtb(
5589 '226_fit_split_elf.dts',
5590 entry_args=entry_args,
5591 extra_indirs=[test_subdir])[0]
5592 self.assertIn(
5593 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5594 str(exc.exception))
5595
Simon Glass40c8bdd2022-03-05 20:19:12 -07005596 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005597 """Test an split-elf FIT with a missing ELF file
5598
5599 Args:
5600 kwargs (dict of str): Arguments to pass to _DoTestFile()
5601
5602 Returns:
5603 tuple:
5604 str: stdout result
5605 str: stderr result
5606 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005607 entry_args = {
5608 'of-list': 'test-fdt1 test-fdt2',
5609 'default-dt': 'test-fdt2',
5610 'atf-bl31-path': 'bl31.elf',
5611 'tee-os-path': 'missing.elf',
5612 }
5613 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5614 with test_util.capture_sys_output() as (stdout, stderr):
5615 self._DoTestFile(
5616 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005617 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5618 out = stdout.getvalue()
5619 err = stderr.getvalue()
5620 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005621
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005622 def testFitSplitElfBadDirective(self):
5623 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5624 if not elf.ELF_TOOLS:
5625 self.skipTest('Python elftools not available')
5626 err = self._check_bad_fit('227_fit_bad_dir.dts')
5627 self.assertIn(
5628 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5629 err)
5630
5631 def testFitSplitElfBadDirectiveConfig(self):
5632 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5633 if not elf.ELF_TOOLS:
5634 self.skipTest('Python elftools not available')
5635 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5636 self.assertEqual(
5637 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5638 err)
5639
5640
Simon Glass40c8bdd2022-03-05 20:19:12 -07005641 def testFitSplitElfMissing(self):
5642 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005643 if not elf.ELF_TOOLS:
5644 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005645 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005646 self.assertRegex(
5647 err,
5648 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005649 self.assertNotRegex(out, '.*Faked blob.*')
5650 fname = tools.get_output_filename('binman-fake/missing.elf')
5651 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005652
5653 def testFitSplitElfFaked(self):
5654 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005655 if not elf.ELF_TOOLS:
5656 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005657 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005658 self.assertRegex(
5659 err,
5660 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005661 self.assertRegex(
5662 out,
5663 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5664 fname = tools.get_output_filename('binman-fake/missing.elf')
5665 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005666
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005667 def testMkimageMissingBlob(self):
5668 """Test using mkimage to build an image"""
5669 with test_util.capture_sys_output() as (stdout, stderr):
5670 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5671 allow_fake_blobs=True)
5672 err = stderr.getvalue()
5673 self.assertRegex(
5674 err,
5675 "Image '.*' has faked external blobs and is non-functional: .*")
5676
Philippe Reynesb1c50932022-03-28 22:57:04 +02005677 def testPreLoad(self):
5678 """Test an image with a pre-load header"""
5679 entry_args = {
Simon Glassefda8ab2023-07-24 09:19:57 -06005680 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesb1c50932022-03-28 22:57:04 +02005681 }
Simon Glassefda8ab2023-07-24 09:19:57 -06005682 data = self._DoReadFileDtb(
5683 '230_pre_load.dts', entry_args=entry_args,
5684 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005685 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5686 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5687 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5688
Simon Glassefda8ab2023-07-24 09:19:57 -06005689 def testPreLoadNoKey(self):
5690 """Test an image with a pre-load heade0r with missing key"""
5691 with self.assertRaises(FileNotFoundError) as exc:
5692 self._DoReadFile('230_pre_load.dts')
5693 self.assertIn("No such file or directory: 'dev.key'",
5694 str(exc.exception))
5695
Philippe Reynesb1c50932022-03-28 22:57:04 +02005696 def testPreLoadPkcs(self):
5697 """Test an image with a pre-load header with padding pkcs"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005698 entry_args = {
5699 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5700 }
5701 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5702 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005703 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5704 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5705 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5706
5707 def testPreLoadPss(self):
5708 """Test an image with a pre-load header with padding pss"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005709 entry_args = {
5710 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5711 }
5712 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5713 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005714 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5715 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5716 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5717
5718 def testPreLoadInvalidPadding(self):
5719 """Test an image with a pre-load header with an invalid padding"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005720 entry_args = {
5721 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5722 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005723 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005724 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5725 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005726
5727 def testPreLoadInvalidSha(self):
5728 """Test an image with a pre-load header with an invalid hash"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005729 entry_args = {
5730 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5731 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005732 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005733 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5734 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005735
5736 def testPreLoadInvalidAlgo(self):
5737 """Test an image with a pre-load header with an invalid algo"""
5738 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005739 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005740
5741 def testPreLoadInvalidKey(self):
5742 """Test an image with a pre-load header with an invalid key"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005743 entry_args = {
5744 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5745 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005746 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005747 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5748 entry_args=entry_args)
Roger Quadros47f420a2022-02-19 20:50:04 +02005749
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005750 def _CheckSafeUniqueNames(self, *images):
5751 """Check all entries of given images for unsafe unique names"""
5752 for image in images:
5753 entries = {}
5754 image._CollectEntries(entries, {}, image)
5755 for entry in entries.values():
5756 uniq = entry.GetUniqueName()
5757
5758 # Used as part of a filename, so must not be absolute paths.
5759 self.assertFalse(os.path.isabs(uniq))
5760
5761 def testSafeUniqueNames(self):
5762 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005763 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005764
5765 orig_image = control.images['image']
5766 image_fname = tools.get_output_filename('image.bin')
5767 image = Image.FromFile(image_fname)
5768
5769 self._CheckSafeUniqueNames(orig_image, image)
5770
5771 def testSafeUniqueNamesMulti(self):
5772 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005773 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005774
5775 orig_image = control.images['image']
5776 image_fname = tools.get_output_filename('image.bin')
5777 image = Image.FromFile(image_fname)
5778
5779 self._CheckSafeUniqueNames(orig_image, image)
5780
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005781 def testReplaceCmdWithBintool(self):
5782 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005783 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005784 expected = U_BOOT_DATA + b'aa'
5785 self.assertEqual(expected, data[:len(expected)])
5786
5787 try:
5788 tmpdir, updated_fname = self._SetupImageInTmpdir()
5789 fname = os.path.join(tmpdir, 'update-testing.bin')
5790 tools.write_file(fname, b'zz')
5791 self._DoBinman('replace', '-i', updated_fname,
5792 '_testing', '-f', fname)
5793
5794 data = tools.read_file(updated_fname)
5795 expected = U_BOOT_DATA + b'zz'
5796 self.assertEqual(expected, data[:len(expected)])
5797 finally:
5798 shutil.rmtree(tmpdir)
5799
5800 def testReplaceCmdOtherWithBintool(self):
5801 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005802 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005803 expected = U_BOOT_DATA + b'aa'
5804 self.assertEqual(expected, data[:len(expected)])
5805
5806 try:
5807 tmpdir, updated_fname = self._SetupImageInTmpdir()
5808 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5809 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5810 self._DoBinman('replace', '-i', updated_fname,
5811 'u-boot', '-f', fname)
5812
5813 data = tools.read_file(updated_fname)
5814 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5815 self.assertEqual(expected, data[:len(expected)])
5816 finally:
5817 shutil.rmtree(tmpdir)
5818
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005819 def testReplaceResizeNoRepackSameSize(self):
5820 """Test replacing entries with same-size data without repacking"""
5821 expected = b'x' * len(U_BOOT_DATA)
5822 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5823 self.assertEqual(expected, data)
5824
5825 path, fdtmap = state.GetFdtContents('fdtmap')
5826 self.assertIsNotNone(path)
5827 self.assertEqual(expected_fdtmap, fdtmap)
5828
5829 def testReplaceResizeNoRepackSmallerSize(self):
5830 """Test replacing entries with smaller-size data without repacking"""
5831 new_data = b'x'
5832 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5833 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5834 self.assertEqual(expected, data)
5835
5836 path, fdtmap = state.GetFdtContents('fdtmap')
5837 self.assertIsNotNone(path)
5838 self.assertEqual(expected_fdtmap, fdtmap)
5839
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005840 def testExtractFit(self):
5841 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005842 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005843 image_fname = tools.get_output_filename('image.bin')
5844
5845 fit_data = control.ReadEntry(image_fname, 'fit')
5846 fit = fdt.Fdt.FromData(fit_data)
5847 fit.Scan()
5848
5849 # Check subentry data inside the extracted fit
5850 for node_path, expected in [
5851 ('/images/kernel', U_BOOT_DATA),
5852 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5853 ('/images/scr-1', COMPRESS_DATA),
5854 ]:
5855 node = fit.GetNode(node_path)
5856 data = fit.GetProps(node)['data'].bytes
5857 self.assertEqual(expected, data)
5858
5859 def testExtractFitSubentries(self):
5860 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005861 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005862 image_fname = tools.get_output_filename('image.bin')
5863
5864 for entry_path, expected in [
5865 ('fit/kernel', U_BOOT_DATA),
5866 ('fit/kernel/u-boot', U_BOOT_DATA),
5867 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5868 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5869 ('fit/scr-1', COMPRESS_DATA),
5870 ('fit/scr-1/blob', COMPRESS_DATA),
5871 ]:
5872 data = control.ReadEntry(image_fname, entry_path)
5873 self.assertEqual(expected, data)
5874
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005875 def testReplaceFitSubentryLeafSameSize(self):
5876 """Test replacing a FIT leaf subentry with same-size data"""
5877 new_data = b'x' * len(U_BOOT_DATA)
5878 data, expected_fdtmap, _ = self._RunReplaceCmd(
5879 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005880 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005881 self.assertEqual(new_data, data)
5882
5883 path, fdtmap = state.GetFdtContents('fdtmap')
5884 self.assertIsNotNone(path)
5885 self.assertEqual(expected_fdtmap, fdtmap)
5886
5887 def testReplaceFitSubentryLeafBiggerSize(self):
5888 """Test replacing a FIT leaf subentry with bigger-size data"""
5889 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5890 data, expected_fdtmap, _ = self._RunReplaceCmd(
5891 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005892 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005893 self.assertEqual(new_data, data)
5894
5895 # Will be repacked, so fdtmap must change
5896 path, fdtmap = state.GetFdtContents('fdtmap')
5897 self.assertIsNotNone(path)
5898 self.assertNotEqual(expected_fdtmap, fdtmap)
5899
5900 def testReplaceFitSubentryLeafSmallerSize(self):
5901 """Test replacing a FIT leaf subentry with smaller-size data"""
5902 new_data = b'x'
5903 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5904 data, expected_fdtmap, _ = self._RunReplaceCmd(
5905 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005906 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005907 self.assertEqual(expected, data)
5908
5909 path, fdtmap = state.GetFdtContents('fdtmap')
5910 self.assertIsNotNone(path)
5911 self.assertEqual(expected_fdtmap, fdtmap)
5912
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005913 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005914 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005915 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005916 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5917 new_data, dts='241_replace_section_simple.dts')
5918 self.assertEqual(new_data, data)
5919
5920 entries = image.GetEntries()
5921 self.assertIn('section', entries)
5922 entry = entries['section']
5923 self.assertEqual(len(new_data), entry.size)
5924
5925 def testReplaceSectionLarger(self):
5926 """Test replacing a simple section with larger data"""
5927 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5928 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5929 new_data, dts='241_replace_section_simple.dts')
5930 self.assertEqual(new_data, data)
5931
5932 entries = image.GetEntries()
5933 self.assertIn('section', entries)
5934 entry = entries['section']
5935 self.assertEqual(len(new_data), entry.size)
5936 fentry = entries['fdtmap']
5937 self.assertEqual(entry.offset + entry.size, fentry.offset)
5938
5939 def testReplaceSectionSmaller(self):
5940 """Test replacing a simple section with smaller data"""
5941 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5942 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5943 new_data, dts='241_replace_section_simple.dts')
5944 self.assertEqual(new_data, data)
5945
5946 # The new size is the same as the old, just with a pad byte at the end
5947 entries = image.GetEntries()
5948 self.assertIn('section', entries)
5949 entry = entries['section']
5950 self.assertEqual(len(new_data), entry.size)
5951
5952 def testReplaceSectionSmallerAllow(self):
5953 """Test failing to replace a simple section with smaller data"""
5954 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5955 try:
5956 state.SetAllowEntryContraction(True)
5957 with self.assertRaises(ValueError) as exc:
5958 self._RunReplaceCmd('section', new_data,
5959 dts='241_replace_section_simple.dts')
5960 finally:
5961 state.SetAllowEntryContraction(False)
5962
5963 # Since we have no information about the position of things within the
5964 # section, we cannot adjust the position of /section-u-boot so it ends
5965 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005966 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005967 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5968 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005969 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005970
Simon Glassdfe1db42022-08-13 11:40:48 -06005971 def testMkimageImagename(self):
5972 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005973 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005974 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005975
5976 # Check that the data appears in the file somewhere
5977 self.assertIn(U_BOOT_SPL_DATA, data)
5978
Simon Glassf3543e62022-09-06 20:26:52 -06005979 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005980 name = data[0x20:0x40]
5981
5982 # Build the filename that we expect to be placed in there, by virtue of
5983 # the -n paraameter
5984 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5985
5986 # Check that the image name is set to the temporary filename used
5987 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5988
Simon Glass9db9e932022-08-13 11:40:49 -06005989 def testMkimageImage(self):
5990 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005991 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005992 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005993
5994 # Check that the data appears in the file somewhere
5995 self.assertIn(U_BOOT_SPL_DATA, data)
5996
Simon Glassf3543e62022-09-06 20:26:52 -06005997 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06005998 name = data[0x20:0x40]
5999
6000 # Build the filename that we expect to be placed in there, by virtue of
6001 # the -n paraameter
6002 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6003
6004 # Check that the image name is set to the temporary filename used
6005 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6006
6007 # Check the corect data is in the imagename file
6008 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6009
6010 def testMkimageImageNoContent(self):
6011 """Test using mkimage with -n and no data"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006012 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006013 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006014 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006015 self.assertIn('Could not complete processing of contents',
6016 str(exc.exception))
6017
6018 def testMkimageImageBad(self):
6019 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006020 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006021 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006022 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006023 self.assertIn('Cannot use both imagename node and data-to-imagename',
6024 str(exc.exception))
6025
Simon Glassd626e822022-08-13 11:40:50 -06006026 def testCollectionOther(self):
6027 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006028 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006029 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6030 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6031 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6032 data)
6033
6034 def testMkimageCollection(self):
6035 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006036 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006037 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006038 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6039 self.assertEqual(expect, data[:len(expect)])
6040
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006041 def testCompressDtbPrependInvalid(self):
6042 """Test that invalid header is detected"""
6043 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006044 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006045 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6046 "'u-boot-dtb': 'invalid'", str(e.exception))
6047
6048 def testCompressDtbPrependLength(self):
6049 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006050 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006051 image = control.images['image']
6052 entries = image.GetEntries()
6053 self.assertIn('u-boot-dtb', entries)
6054 u_boot_dtb = entries['u-boot-dtb']
6055 self.assertIn('fdtmap', entries)
6056 fdtmap = entries['fdtmap']
6057
6058 image_fname = tools.get_output_filename('image.bin')
6059 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6060 dtb = fdt.Fdt.FromData(orig)
6061 dtb.Scan()
6062 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6063 expected = {
6064 'u-boot:size': len(U_BOOT_DATA),
6065 'u-boot-dtb:uncomp-size': len(orig),
6066 'u-boot-dtb:size': u_boot_dtb.size,
6067 'fdtmap:size': fdtmap.size,
6068 'size': len(data),
6069 }
6070 self.assertEqual(expected, props)
6071
6072 # Check implementation
6073 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6074 rest = data[len(U_BOOT_DATA):]
6075 comp_data_len = struct.unpack('<I', rest[:4])[0]
6076 comp_data = rest[4:4 + comp_data_len]
6077 orig2 = self._decompress(comp_data)
6078 self.assertEqual(orig, orig2)
6079
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006080 def testInvalidCompress(self):
6081 """Test that invalid compress algorithm is detected"""
6082 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006083 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006084 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6085
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006086 def testCompUtilCompressions(self):
6087 """Test compression algorithms"""
6088 for bintool in self.comp_bintools.values():
6089 self._CheckBintool(bintool)
6090 data = bintool.compress(COMPRESS_DATA)
6091 self.assertNotEqual(COMPRESS_DATA, data)
6092 orig = bintool.decompress(data)
6093 self.assertEquals(COMPRESS_DATA, orig)
6094
6095 def testCompUtilVersions(self):
6096 """Test tool version of compression algorithms"""
6097 for bintool in self.comp_bintools.values():
6098 self._CheckBintool(bintool)
6099 version = bintool.version()
6100 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6101
6102 def testCompUtilPadding(self):
6103 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006104 # Skip zstd because it doesn't support padding
6105 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006106 self._CheckBintool(bintool)
6107 data = bintool.compress(COMPRESS_DATA)
6108 self.assertNotEqual(COMPRESS_DATA, data)
6109 data += tools.get_bytes(0, 64)
6110 orig = bintool.decompress(data)
6111 self.assertEquals(COMPRESS_DATA, orig)
6112
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006113 def testCompressDtbZstd(self):
6114 """Test that zstd compress of device-tree files failed"""
6115 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006116 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006117 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6118 "requires a length header", str(e.exception))
6119
Quentin Schulz4d91df02022-09-02 15:10:48 +02006120 def testMkimageMultipleDataFiles(self):
6121 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006122 self._SetupSplElf()
6123 self._SetupTplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006124 data = self._DoReadFile('252_mkimage_mult_data.dts')
6125 # Size of files are packed in their 4B big-endian format
6126 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6127 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6128 # Size info is always followed by a 4B zero value.
6129 expect += tools.get_bytes(0, 4)
6130 expect += U_BOOT_TPL_DATA
6131 # All but last files are 4B-aligned
6132 align_pad = len(U_BOOT_TPL_DATA) % 4
6133 if align_pad:
6134 expect += tools.get_bytes(0, align_pad)
6135 expect += U_BOOT_SPL_DATA
6136 self.assertEqual(expect, data[-len(expect):])
6137
Marek Vasutfadad3a2023-07-18 07:23:58 -06006138 def testMkimageMultipleExpanded(self):
6139 """Test passing multiple files to mkimage in a mkimage entry"""
6140 self._SetupSplElf()
6141 self._SetupTplElf()
6142 entry_args = {
6143 'spl-bss-pad': 'y',
6144 'spl-dtb': 'y',
6145 }
6146 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6147 use_expanded=True, entry_args=entry_args)[0]
6148 pad_len = 10
6149 tpl_expect = U_BOOT_TPL_DATA
6150 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6151 spl_expect += U_BOOT_SPL_DTB_DATA
6152
6153 content = data[0x40:]
6154 lens = struct.unpack('>III', content[:12])
6155
6156 # Size of files are packed in their 4B big-endian format
6157 # Size info is always followed by a 4B zero value.
6158 self.assertEqual(len(tpl_expect), lens[0])
6159 self.assertEqual(len(spl_expect), lens[1])
6160 self.assertEqual(0, lens[2])
6161
6162 rest = content[12:]
6163 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6164
6165 rest = rest[len(tpl_expect):]
6166 align_pad = len(tpl_expect) % 4
6167 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6168 rest = rest[align_pad:]
6169 self.assertEqual(spl_expect, rest)
6170
Quentin Schulz4d91df02022-09-02 15:10:48 +02006171 def testMkimageMultipleNoContent(self):
6172 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006173 self._SetupSplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006174 with self.assertRaises(ValueError) as exc:
6175 self._DoReadFile('253_mkimage_mult_no_content.dts')
6176 self.assertIn('Could not complete processing of contents',
6177 str(exc.exception))
6178
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006179 def testMkimageFilename(self):
6180 """Test using mkimage to build a binary with a filename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006181 self._SetupSplElf()
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006182 retcode = self._DoTestFile('254_mkimage_filename.dts')
6183 self.assertEqual(0, retcode)
6184 fname = tools.get_output_filename('mkimage-test.bin')
6185 self.assertTrue(os.path.exists(fname))
6186
Simon Glass6ad24522022-02-28 07:16:54 -07006187 def testVpl(self):
6188 """Test that an image with VPL and its device tree can be created"""
6189 # ELF file with a '__bss_size' symbol
6190 self._SetupVplElf()
6191 data = self._DoReadFile('255_u_boot_vpl.dts')
6192 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6193
6194 def testVplNoDtb(self):
6195 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6196 self._SetupVplElf()
6197 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6198 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6199 data[:len(U_BOOT_VPL_NODTB_DATA)])
6200
6201 def testExpandedVpl(self):
6202 """Test that an expanded entry type is selected for TPL when needed"""
6203 self._SetupVplElf()
6204
6205 entry_args = {
6206 'vpl-bss-pad': 'y',
6207 'vpl-dtb': 'y',
6208 }
6209 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6210 entry_args=entry_args)
6211 image = control.images['image']
6212 entries = image.GetEntries()
6213 self.assertEqual(1, len(entries))
6214
6215 # We only have u-boot-vpl, which be expanded
6216 self.assertIn('u-boot-vpl', entries)
6217 entry = entries['u-boot-vpl']
6218 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6219 subent = entry.GetEntries()
6220 self.assertEqual(3, len(subent))
6221 self.assertIn('u-boot-vpl-nodtb', subent)
6222 self.assertIn('u-boot-vpl-bss-pad', subent)
6223 self.assertIn('u-boot-vpl-dtb', subent)
6224
6225 def testVplBssPadMissing(self):
6226 """Test that a missing symbol is detected"""
6227 self._SetupVplElf('u_boot_ucode_ptr')
6228 with self.assertRaises(ValueError) as e:
6229 self._DoReadFile('258_vpl_bss_pad.dts')
6230 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6231 str(e.exception))
6232
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306233 def testSymlink(self):
Andrew Davis15432ea2023-07-22 00:14:44 +05306234 """Test that image files can be symlinked"""
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306235 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6236 self.assertEqual(0, retcode)
6237 image = control.images['test_image']
6238 fname = tools.get_output_filename('test_image.bin')
6239 sname = tools.get_output_filename('symlink_to_test.bin')
6240 self.assertTrue(os.path.islink(sname))
6241 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006242
Andrew Davis15432ea2023-07-22 00:14:44 +05306243 def testSymlinkOverwrite(self):
6244 """Test that symlinked images can be overwritten"""
6245 testdir = TestFunctional._MakeInputDir('symlinktest')
6246 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6247 # build the same image again in the same directory so that existing symlink is present
6248 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6249 fname = tools.get_output_filename('test_image.bin')
6250 sname = tools.get_output_filename('symlink_to_test.bin')
6251 self.assertTrue(os.path.islink(sname))
6252 self.assertEqual(os.readlink(sname), fname)
6253
Simon Glassd2afb9e2022-10-20 18:22:47 -06006254 def testSymbolsElf(self):
6255 """Test binman can assign symbols embedded in an ELF file"""
6256 if not elf.ELF_TOOLS:
6257 self.skipTest('Python elftools not available')
6258 self._SetupTplElf('u_boot_binman_syms')
6259 self._SetupVplElf('u_boot_binman_syms')
6260 self._SetupSplElf('u_boot_binman_syms')
6261 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6262 image_fname = tools.get_output_filename('image.bin')
6263
6264 image = control.images['image']
6265 entries = image.GetEntries()
6266
6267 for entry in entries.values():
6268 # No symbols in u-boot and it has faked contents anyway
6269 if entry.name == 'u-boot':
6270 continue
6271 edata = data[entry.image_pos:entry.image_pos + entry.size]
6272 efname = tools.get_output_filename(f'edata-{entry.name}')
6273 tools.write_file(efname, edata)
6274
6275 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6276 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6277 for name, sym in syms.items():
6278 msg = 'test'
6279 val = elf.GetSymbolValue(sym, edata, msg)
6280 entry_m = re_name.match(name)
6281 if entry_m:
6282 ename, prop = entry_m.group(1), entry_m.group(3)
6283 entry, entry_name, prop_name = image.LookupEntry(entries,
6284 name, msg)
6285 if prop_name == 'offset':
6286 expect_val = entry.offset
6287 elif prop_name == 'image_pos':
6288 expect_val = entry.image_pos
6289 elif prop_name == 'size':
6290 expect_val = entry.size
6291 self.assertEqual(expect_val, val)
6292
6293 def testSymbolsElfBad(self):
6294 """Check error when trying to write symbols without the elftools lib"""
6295 if not elf.ELF_TOOLS:
6296 self.skipTest('Python elftools not available')
6297 self._SetupTplElf('u_boot_binman_syms')
6298 self._SetupVplElf('u_boot_binman_syms')
6299 self._SetupSplElf('u_boot_binman_syms')
6300 try:
6301 elf.ELF_TOOLS = False
6302 with self.assertRaises(ValueError) as exc:
6303 self._DoReadFileDtb('260_symbols_elf.dts')
6304 finally:
6305 elf.ELF_TOOLS = True
6306 self.assertIn(
6307 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6308 'Cannot write symbols to an ELF file without Python elftools',
6309 str(exc.exception))
6310
Simon Glassefddab62023-01-07 14:07:08 -07006311 def testSectionFilename(self):
6312 """Check writing of section contents to a file"""
6313 data = self._DoReadFile('261_section_fname.dts')
6314 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6315 tools.get_bytes(ord('!'), 7) +
6316 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6317 self.assertEqual(expected, data)
6318
6319 sect_fname = tools.get_output_filename('outfile.bin')
6320 self.assertTrue(os.path.exists(sect_fname))
6321 sect_data = tools.read_file(sect_fname)
6322 self.assertEqual(U_BOOT_DATA, sect_data)
6323
Simon Glassc8c9f312023-01-07 14:07:12 -07006324 def testAbsent(self):
6325 """Check handling of absent entries"""
6326 data = self._DoReadFile('262_absent.dts')
6327 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6328
Simon Glass2f80c5e2023-01-07 14:07:14 -07006329 def testPackTeeOsOptional(self):
6330 """Test that an image with an optional TEE binary can be created"""
6331 entry_args = {
6332 'tee-os-path': 'tee.elf',
6333 }
6334 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6335 entry_args=entry_args)[0]
6336 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6337
6338 def checkFitTee(self, dts, tee_fname):
6339 """Check that a tee-os entry works and returns data
6340
6341 Args:
6342 dts (str): Device tree filename to use
6343 tee_fname (str): filename containing tee-os
6344
6345 Returns:
6346 bytes: Image contents
6347 """
6348 if not elf.ELF_TOOLS:
6349 self.skipTest('Python elftools not available')
6350 entry_args = {
6351 'of-list': 'test-fdt1 test-fdt2',
6352 'default-dt': 'test-fdt2',
6353 'tee-os-path': tee_fname,
6354 }
6355 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6356 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6357 extra_indirs=[test_subdir])[0]
6358 return data
6359
6360 def testFitTeeOsOptionalFit(self):
6361 """Test an image with a FIT with an optional OP-TEE binary"""
6362 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6363
6364 # There should be only one node, holding the data set up in SetUpClass()
6365 # for tee.bin
6366 dtb = fdt.Fdt.FromData(data)
6367 dtb.Scan()
6368 node = dtb.GetNode('/images/tee-1')
6369 self.assertEqual(TEE_ADDR,
6370 fdt_util.fdt32_to_cpu(node.props['load'].value))
6371 self.assertEqual(TEE_ADDR,
6372 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6373 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6374
Jonas Karlman49dcd1c2023-07-18 20:34:36 +00006375 with test_util.capture_sys_output() as (stdout, stderr):
6376 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6377 err = stderr.getvalue()
6378 self.assertRegex(
6379 err,
6380 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6381
Simon Glass2f80c5e2023-01-07 14:07:14 -07006382 def testFitTeeOsOptionalFitBad(self):
6383 """Test an image with a FIT with an optional OP-TEE binary"""
6384 with self.assertRaises(ValueError) as exc:
6385 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6386 self.assertIn(
6387 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6388 str(exc.exception))
6389
6390 def testFitTeeOsBad(self):
6391 """Test an OP-TEE binary with wrong formats"""
6392 self.make_tee_bin('tee.bad1', 123)
6393 with self.assertRaises(ValueError) as exc:
6394 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6395 self.assertIn(
6396 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6397 str(exc.exception))
6398
6399 self.make_tee_bin('tee.bad2', 0, b'extra data')
6400 with self.assertRaises(ValueError) as exc:
6401 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6402 self.assertIn(
6403 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6404 str(exc.exception))
6405
Simon Glass67a05012023-01-07 14:07:15 -07006406 def testExtblobOptional(self):
6407 """Test an image with an external blob that is optional"""
6408 with test_util.capture_sys_output() as (stdout, stderr):
6409 data = self._DoReadFile('266_blob_ext_opt.dts')
6410 self.assertEqual(REFCODE_DATA, data)
6411 err = stderr.getvalue()
6412 self.assertRegex(
6413 err,
Jonas Karlman05dec372023-07-18 20:34:34 +00006414 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass67a05012023-01-07 14:07:15 -07006415
Simon Glass0b079fc2023-01-11 16:10:12 -07006416 def testSectionInner(self):
6417 """Test an inner section with a size"""
6418 data = self._DoReadFile('267_section_inner.dts')
6419 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6420 self.assertEqual(expected, data)
6421
Simon Glass62ef2f72023-01-11 16:10:14 -07006422 def testNull(self):
6423 """Test an image with a null entry"""
6424 data = self._DoReadFile('268_null.dts')
6425 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6426
Simon Glass9766f692023-01-11 16:10:16 -07006427 def testOverlap(self):
6428 """Test an image with a overlapping entry"""
6429 data = self._DoReadFile('269_overlap.dts')
6430 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6431
6432 image = control.images['image']
6433 entries = image.GetEntries()
6434
6435 self.assertIn('inset', entries)
6436 inset = entries['inset']
6437 self.assertEqual(1, inset.offset);
6438 self.assertEqual(1, inset.image_pos);
6439 self.assertEqual(2, inset.size);
6440
6441 def testOverlapNull(self):
6442 """Test an image with a null overlap"""
6443 data = self._DoReadFile('270_overlap_null.dts')
6444 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6445
6446 # Check the FMAP
6447 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6448 self.assertEqual(4, fhdr.nareas)
6449 fiter = iter(fentries)
6450
6451 fentry = next(fiter)
6452 self.assertEqual(b'SECTION', fentry.name)
6453 self.assertEqual(0, fentry.offset)
6454 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6455 self.assertEqual(0, fentry.flags)
6456
6457 fentry = next(fiter)
6458 self.assertEqual(b'U_BOOT', fentry.name)
6459 self.assertEqual(0, fentry.offset)
6460 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6461 self.assertEqual(0, fentry.flags)
6462
6463 # Make sure that the NULL entry appears in the FMAP
6464 fentry = next(fiter)
6465 self.assertEqual(b'NULL', fentry.name)
6466 self.assertEqual(1, fentry.offset)
6467 self.assertEqual(2, fentry.size)
6468 self.assertEqual(0, fentry.flags)
6469
6470 fentry = next(fiter)
6471 self.assertEqual(b'FMAP', fentry.name)
6472 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6473
6474 def testOverlapBad(self):
6475 """Test an image with a bad overlapping entry"""
6476 with self.assertRaises(ValueError) as exc:
6477 self._DoReadFile('271_overlap_bad.dts')
6478 self.assertIn(
6479 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6480 str(exc.exception))
6481
6482 def testOverlapNoOffset(self):
6483 """Test an image with a bad overlapping entry"""
6484 with self.assertRaises(ValueError) as exc:
6485 self._DoReadFile('272_overlap_no_size.dts')
6486 self.assertIn(
6487 "Node '/binman/inset': 'fill' entry is missing properties: size",
6488 str(exc.exception))
6489
Simon Glassc1157862023-01-11 16:10:17 -07006490 def testBlobSymbol(self):
6491 """Test a blob with symbols read from an ELF file"""
6492 elf_fname = self.ElfTestFile('blob_syms')
6493 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6494 TestFunctional._MakeInputFile('blob_syms.bin',
6495 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6496
6497 data = self._DoReadFile('273_blob_symbol.dts')
6498
6499 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6500 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6501 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6502 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6503 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6504
6505 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6506 expected = sym_values
6507 self.assertEqual(expected, data[:len(expected)])
6508
Simon Glass571bc4e2023-01-11 16:10:19 -07006509 def testOffsetFromElf(self):
6510 """Test a blob with symbols read from an ELF file"""
6511 elf_fname = self.ElfTestFile('blob_syms')
6512 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6513 TestFunctional._MakeInputFile('blob_syms.bin',
6514 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6515
6516 data = self._DoReadFile('274_offset_from_elf.dts')
6517
6518 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6519 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6520
6521 image = control.images['image']
6522 entries = image.GetEntries()
6523
6524 self.assertIn('inset', entries)
6525 inset = entries['inset']
6526
6527 self.assertEqual(base + 4, inset.offset);
6528 self.assertEqual(base + 4, inset.image_pos);
6529 self.assertEqual(4, inset.size);
6530
6531 self.assertIn('inset2', entries)
6532 inset = entries['inset2']
6533 self.assertEqual(base + 8, inset.offset);
6534 self.assertEqual(base + 8, inset.image_pos);
6535 self.assertEqual(4, inset.size);
6536
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006537 def testFitAlign(self):
6538 """Test an image with an FIT with aligned external data"""
6539 data = self._DoReadFile('275_fit_align.dts')
6540 self.assertEqual(4096, len(data))
6541
6542 dtb = fdt.Fdt.FromData(data)
6543 dtb.Scan()
6544
6545 props = self._GetPropTree(dtb, ['data-position'])
6546 expected = {
6547 'u-boot:data-position': 1024,
6548 'fdt-1:data-position': 2048,
6549 'fdt-2:data-position': 3072,
6550 }
6551 self.assertEqual(expected, props)
6552
Jonas Karlmanf584d442023-01-21 19:02:12 +00006553 def testFitFirmwareLoadables(self):
6554 """Test an image with an FIT that use fit,firmware"""
6555 if not elf.ELF_TOOLS:
6556 self.skipTest('Python elftools not available')
6557 entry_args = {
6558 'of-list': 'test-fdt1',
6559 'default-dt': 'test-fdt1',
6560 'atf-bl31-path': 'bl31.elf',
6561 'tee-os-path': 'missing.bin',
6562 }
6563 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006564 with test_util.capture_sys_output() as (stdout, stderr):
6565 data = self._DoReadFileDtb(
6566 '276_fit_firmware_loadables.dts',
6567 entry_args=entry_args,
6568 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006569
6570 dtb = fdt.Fdt.FromData(data)
6571 dtb.Scan()
6572
6573 node = dtb.GetNode('/configurations/conf-uboot-1')
6574 self.assertEqual('u-boot', node.props['firmware'].value)
6575 self.assertEqual(['atf-1', 'atf-2'],
6576 fdt_util.GetStringList(node, 'loadables'))
6577
6578 node = dtb.GetNode('/configurations/conf-atf-1')
6579 self.assertEqual('atf-1', node.props['firmware'].value)
6580 self.assertEqual(['u-boot', 'atf-2'],
6581 fdt_util.GetStringList(node, 'loadables'))
6582
6583 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6584 self.assertEqual('u-boot', node.props['firmware'].value)
6585 self.assertEqual(['atf-1', 'atf-2'],
6586 fdt_util.GetStringList(node, 'loadables'))
6587
6588 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6589 self.assertEqual('atf-1', node.props['firmware'].value)
6590 self.assertEqual(['u-boot', 'atf-2'],
6591 fdt_util.GetStringList(node, 'loadables'))
6592
6593 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6594 self.assertEqual('atf-1', node.props['firmware'].value)
6595 self.assertEqual(['u-boot', 'atf-2'],
6596 fdt_util.GetStringList(node, 'loadables'))
6597
Simon Glassfe7e9242023-02-22 12:14:49 -07006598 def testTooldir(self):
6599 """Test that we can specify the tooldir"""
6600 with test_util.capture_sys_output() as (stdout, stderr):
6601 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6602 'tool', '-l'))
6603 self.assertEqual('fred', bintool.Bintool.tooldir)
6604
6605 # Check that the toolpath is updated correctly
6606 self.assertEqual(['fred'], tools.tool_search_paths)
6607
6608 # Try with a few toolpaths; the tooldir should be at the end
6609 with test_util.capture_sys_output() as (stdout, stderr):
6610 self.assertEqual(0, self._DoBinman(
6611 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6612 'tool', '-l'))
6613 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6614
Simon Glass7caa3722023-03-02 17:02:44 -07006615 def testReplaceSectionEntry(self):
6616 """Test replacing an entry in a section"""
6617 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6618 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6619 expect_data, dts='241_replace_section_simple.dts')
6620 self.assertEqual(expect_data, entry_data)
6621
6622 entries = image.GetEntries()
6623 self.assertIn('section', entries)
6624 section = entries['section']
6625
6626 sect_entries = section.GetEntries()
6627 self.assertIn('blob', sect_entries)
6628 entry = sect_entries['blob']
6629 self.assertEqual(len(expect_data), entry.size)
6630
6631 fname = tools.get_output_filename('image-updated.bin')
6632 data = tools.read_file(fname)
6633
6634 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6635 self.assertEqual(expect_data, new_blob_data)
6636
6637 self.assertEqual(U_BOOT_DATA,
6638 data[entry.image_pos + len(expect_data):]
6639 [:len(U_BOOT_DATA)])
6640
6641 def testReplaceSectionDeep(self):
6642 """Test replacing an entry in two levels of sections"""
6643 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6644 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6645 'section/section/blob', expect_data,
6646 dts='278_replace_section_deep.dts')
6647 self.assertEqual(expect_data, entry_data)
6648
6649 entries = image.GetEntries()
6650 self.assertIn('section', entries)
6651 section = entries['section']
6652
6653 subentries = section.GetEntries()
6654 self.assertIn('section', subentries)
6655 section = subentries['section']
6656
6657 sect_entries = section.GetEntries()
6658 self.assertIn('blob', sect_entries)
6659 entry = sect_entries['blob']
6660 self.assertEqual(len(expect_data), entry.size)
6661
6662 fname = tools.get_output_filename('image-updated.bin')
6663 data = tools.read_file(fname)
6664
6665 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6666 self.assertEqual(expect_data, new_blob_data)
6667
6668 self.assertEqual(U_BOOT_DATA,
6669 data[entry.image_pos + len(expect_data):]
6670 [:len(U_BOOT_DATA)])
6671
6672 def testReplaceFitSibling(self):
6673 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006674 self._SetupSplElf()
Simon Glass7caa3722023-03-02 17:02:44 -07006675 fname = TestFunctional._MakeInputFile('once', b'available once')
6676 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6677 os.remove(fname)
6678
6679 try:
6680 tmpdir, updated_fname = self._SetupImageInTmpdir()
6681
6682 fname = os.path.join(tmpdir, 'update-blob')
6683 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6684 tools.write_file(fname, expected)
6685
6686 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6687 data = tools.read_file(updated_fname)
6688 start = len(U_BOOT_DTB_DATA)
6689 self.assertEqual(expected, data[start:start + len(expected)])
6690 map_fname = os.path.join(tmpdir, 'image-updated.map')
6691 self.assertFalse(os.path.exists(map_fname))
6692 finally:
6693 shutil.rmtree(tmpdir)
6694
Simon Glass953d4172023-03-02 17:02:45 -07006695 def testX509Cert(self):
6696 """Test creating an X509 certificate"""
6697 keyfile = self.TestFile('key.key')
6698 entry_args = {
6699 'keyfile': keyfile,
6700 }
6701 data = self._DoReadFileDtb('279_x509_cert.dts',
6702 entry_args=entry_args)[0]
6703 cert = data[:-4]
6704 self.assertEqual(U_BOOT_DATA, data[-4:])
6705
6706 # TODO: verify the signature
6707
6708 def testX509CertMissing(self):
6709 """Test that binman still produces an image if openssl is missing"""
6710 keyfile = self.TestFile('key.key')
6711 entry_args = {
6712 'keyfile': 'keyfile',
6713 }
6714 with test_util.capture_sys_output() as (_, stderr):
6715 self._DoTestFile('279_x509_cert.dts',
6716 force_missing_bintools='openssl',
6717 entry_args=entry_args)
6718 err = stderr.getvalue()
6719 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6720
Jonas Karlman05b978b2023-02-25 19:01:33 +00006721 def testPackRockchipTpl(self):
6722 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glass176f1f62023-07-24 09:19:58 -06006723 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman05b978b2023-02-25 19:01:33 +00006724 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6725
Jonas Karlman40389c22023-02-25 19:01:35 +00006726 def testMkimageMissingBlobMultiple(self):
6727 """Test missing blob with mkimage entry and multiple-data-files"""
6728 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass176f1f62023-07-24 09:19:58 -06006729 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman40389c22023-02-25 19:01:35 +00006730 err = stderr.getvalue()
6731 self.assertIn("is missing external blobs and is non-functional", err)
6732
6733 with self.assertRaises(ValueError) as e:
Simon Glass176f1f62023-07-24 09:19:58 -06006734 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman40389c22023-02-25 19:01:35 +00006735 self.assertIn("not found in input path", str(e.exception))
6736
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006737 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6738 """Prepare sign environment
6739
6740 Create private and public keys, add pubkey into dtb.
6741
6742 Returns:
6743 Tuple:
6744 FIT container
6745 Image name
6746 Private key
6747 DTB
6748 """
Marek Vasutfadad3a2023-07-18 07:23:58 -06006749 self._SetupSplElf()
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006750 data = self._DoReadFileRealDtb(dts)
6751 updated_fname = tools.get_output_filename('image-updated.bin')
6752 tools.write_file(updated_fname, data)
6753 dtb = tools.get_output_filename('source.dtb')
6754 private_key = tools.get_output_filename('test_key.key')
6755 public_key = tools.get_output_filename('test_key.crt')
6756 fit = tools.get_output_filename('fit.fit')
6757 key_dir = tools.get_output_dir()
6758
6759 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6760 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6761 private_key, '-out', public_key)
6762 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6763 '-n', 'test_key', '-r', 'conf', dtb)
6764
6765 return fit, updated_fname, private_key, dtb
6766
6767 def testSignSimple(self):
6768 """Test that a FIT container can be signed in image"""
6769 is_signed = False
6770 fit, fname, private_key, dtb = self._PrepareSignEnv()
6771
6772 # do sign with private key
6773 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6774 ['fit'])
6775 is_signed = self._CheckSign(fit, dtb)
6776
6777 self.assertEqual(is_signed, True)
6778
6779 def testSignExactFIT(self):
6780 """Test that a FIT container can be signed and replaced in image"""
6781 is_signed = False
6782 fit, fname, private_key, dtb = self._PrepareSignEnv()
6783
6784 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6785 args = []
6786 if self.toolpath:
6787 for path in self.toolpath:
6788 args += ['--toolpath', path]
6789
6790 # do sign with private key
6791 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6792 'sha256,rsa4096', '-f', fit, 'fit')
6793 is_signed = self._CheckSign(fit, dtb)
6794
6795 self.assertEqual(is_signed, True)
6796
6797 def testSignNonFit(self):
6798 """Test a non-FIT entry cannot be signed"""
6799 is_signed = False
6800 fit, fname, private_key, _ = self._PrepareSignEnv(
6801 '281_sign_non_fit.dts')
6802
6803 # do sign with private key
6804 with self.assertRaises(ValueError) as e:
6805 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6806 'sha256,rsa4096', '-f', fit, 'u-boot')
6807 self.assertIn(
6808 "Node '/u-boot': Updating signatures is not supported with this entry type",
6809 str(e.exception))
6810
6811 def testSignMissingMkimage(self):
6812 """Test that FIT signing handles a missing mkimage tool"""
6813 fit, fname, private_key, _ = self._PrepareSignEnv()
6814
6815 # try to sign with a missing mkimage tool
6816 bintool.Bintool.set_missing_list(['mkimage'])
6817 with self.assertRaises(ValueError) as e:
6818 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6819 ['fit'])
6820 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6821
Simon Glass4649bea2023-07-18 07:23:54 -06006822 def testSymbolNoWrite(self):
6823 """Test disabling of symbol writing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006824 self._SetupSplElf()
Simon Glass4649bea2023-07-18 07:23:54 -06006825 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6826 no_write_symbols=True)
6827
6828 def testSymbolNoWriteExpanded(self):
6829 """Test disabling of symbol writing in expanded entries"""
6830 entry_args = {
6831 'spl-dtb': '1',
6832 }
6833 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6834 U_BOOT_SPL_DTB_DATA, 0x38,
6835 entry_args=entry_args, use_expanded=True,
6836 no_write_symbols=True)
6837
Marek Vasutfadad3a2023-07-18 07:23:58 -06006838 def testMkimageSpecial(self):
6839 """Test mkimage ignores special hash-1 node"""
6840 data = self._DoReadFile('283_mkimage_special.dts')
6841
6842 # Just check that the data appears in the file somewhere
6843 self.assertIn(U_BOOT_DATA, data)
6844
Simon Glassb1e40ee2023-07-18 07:23:59 -06006845 def testFitFdtList(self):
6846 """Test an image with an FIT with the fit,fdt-list-val option"""
6847 entry_args = {
6848 'default-dt': 'test-fdt2',
6849 }
6850 data = self._DoReadFileDtb(
6851 '284_fit_fdt_list.dts',
6852 entry_args=entry_args,
6853 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6854 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6855 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6856
Simon Glasse1ad57e2023-07-18 07:24:01 -06006857 def testSplEmptyBss(self):
6858 """Test an expanded SPL with a zero-size BSS"""
6859 # ELF file with a '__bss_size' symbol
6860 self._SetupSplElf(src_fname='bss_data_zero')
6861
6862 entry_args = {
6863 'spl-bss-pad': 'y',
6864 'spl-dtb': 'y',
6865 }
6866 data = self._DoReadFileDtb('285_spl_expand.dts',
6867 use_expanded=True, entry_args=entry_args)[0]
6868
Simon Glassf6abd522023-07-18 07:24:04 -06006869 def testTemplate(self):
6870 """Test using a template"""
6871 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6872 data = self._DoReadFile('286_template.dts')
6873 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6874 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6875 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6876
Simon Glassb2f47a52023-07-22 21:43:52 -06006877 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6878 self.assertTrue(os.path.exists(dtb_fname1))
6879 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6880 dtb.Scan()
6881 node1 = dtb.GetNode('/binman/template')
6882 self.assertTrue(node1)
6883 vga = dtb.GetNode('/binman/first/intel-vga')
6884 self.assertTrue(vga)
6885
Simon Glassaf41b242023-07-22 21:43:56 -06006886 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6887 self.assertTrue(os.path.exists(dtb_fname2))
6888 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6889 dtb2.Scan()
6890 node2 = dtb2.GetNode('/binman/template')
6891 self.assertFalse(node2)
6892
Simon Glass35f72fb2023-07-18 07:24:05 -06006893 def testTemplateBlobMulti(self):
6894 """Test using a template with 'multiple-images' enabled"""
6895 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6896 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6897 retcode = self._DoTestFile('287_template_multi.dts')
6898
6899 self.assertEqual(0, retcode)
6900 image = control.images['image']
6901 image_fname = tools.get_output_filename('my-image.bin')
6902 data = tools.read_file(image_fname)
6903 self.assertEqual(b'blob@@@@other', data)
6904
Simon Glassdb0e3f12023-07-18 07:24:06 -06006905 def testTemplateFit(self):
6906 """Test using a template in a FIT"""
6907 fit_data = self._DoReadFile('288_template_fit.dts')
6908 fname = os.path.join(self._indir, 'fit_data.fit')
6909 tools.write_file(fname, fit_data)
6910 out = tools.run('dumpimage', '-l', fname)
6911
Simon Glass696f2b72023-07-18 07:24:07 -06006912 def testTemplateSection(self):
6913 """Test using a template in a section (not at top level)"""
6914 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6915 data = self._DoReadFile('289_template_section.dts')
6916 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6917 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6918 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6919
Simon Glass23b96e92023-07-18 07:24:08 -06006920 def testMkimageSymbols(self):
6921 """Test using mkimage to build an image with symbols in it"""
6922 self._SetupSplElf('u_boot_binman_syms')
6923 data = self._DoReadFile('290_mkimage_sym.dts')
6924
6925 image = control.images['image']
6926 entries = image.GetEntries()
6927 self.assertIn('u-boot', entries)
6928 u_boot = entries['u-boot']
6929
6930 mkim = entries['mkimage']
6931 mkim_entries = mkim.GetEntries()
6932 self.assertIn('u-boot-spl', mkim_entries)
6933 spl = mkim_entries['u-boot-spl']
6934 self.assertIn('u-boot-spl2', mkim_entries)
6935 spl2 = mkim_entries['u-boot-spl2']
6936
6937 # skip the mkimage header and the area sizes
6938 mk_data = data[mkim.offset + 0x40:]
6939 size, term = struct.unpack('>LL', mk_data[:8])
6940
6941 # There should be only one image, so check that the zero terminator is
6942 # present
6943 self.assertEqual(0, term)
6944
6945 content = mk_data[8:8 + size]
6946
6947 # The image should contain the symbols from u_boot_binman_syms.c
6948 # Note that image_pos is adjusted by the base address of the image,
6949 # which is 0x10 in our test image
6950 spl_data = content[:0x18]
6951 content = content[0x1b:]
6952
6953 # After the header is a table of offsets for each image. There should
6954 # only be one image, then a 0 terminator, so figure out the real start
6955 # of the image data
6956 base = 0x40 + 8
6957
6958 # Check symbols in both u-boot-spl and u-boot-spl2
6959 for i in range(2):
6960 vals = struct.unpack('<LLQLL', spl_data)
6961
6962 # The image should contain the symbols from u_boot_binman_syms.c
6963 # Note that image_pos is adjusted by the base address of the image,
6964 # which is 0x10 in our 'u_boot_binman_syms' test image
6965 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6966 self.assertEqual(base, vals[1])
6967 self.assertEqual(spl2.offset, vals[2])
6968 # figure out the internal positions of its components
6969 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6970
6971 # Check that spl and spl2 are actually at the indicated positions
6972 self.assertEqual(
6973 elf.BINMAN_SYM_MAGIC_VALUE,
6974 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6975 self.assertEqual(
6976 elf.BINMAN_SYM_MAGIC_VALUE,
6977 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6978
6979 self.assertEqual(len(U_BOOT_DATA), vals[4])
6980
6981 # Move to next
6982 spl_data = content[:0x18]
6983
Simon Glassd4d97662023-07-22 21:43:57 -06006984 def testTemplatePhandle(self):
6985 """Test using a template in a node containing a phandle"""
6986 entry_args = {
6987 'atf-bl31-path': 'bl31.elf',
6988 }
Simon Glass93a203d2023-08-03 17:23:58 -06006989 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glassd4d97662023-07-22 21:43:57 -06006990 entry_args=entry_args)
6991 fname = tools.get_output_filename('image.bin')
6992 out = tools.run('dumpimage', '-l', fname)
6993
6994 # We should see the FIT description and one for each of the two images
6995 lines = out.splitlines()
6996 descs = [line.split()[-1] for line in lines if 'escription' in line]
6997 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
6998
6999 def testTemplatePhandleDup(self):
7000 """Test using a template in a node containing a phandle"""
7001 entry_args = {
7002 'atf-bl31-path': 'bl31.elf',
7003 }
7004 with self.assertRaises(ValueError) as e:
Simon Glass93a203d2023-08-03 17:23:58 -06007005 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glassd4d97662023-07-22 21:43:57 -06007006 entry_args=entry_args)
7007 self.assertIn(
7008 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7009 str(e.exception))
7010
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307011 def testTIBoardConfig(self):
7012 """Test that a schema validated board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06007013 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307014 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7015
7016 def testTIBoardConfigCombined(self):
7017 """Test that a schema validated combined board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06007018 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307019 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7020 self.assertGreater(data, configlen_noheader)
7021
7022 def testTIBoardConfigNoDataType(self):
7023 """Test that error is thrown when data type is not supported"""
7024 with self.assertRaises(ValueError) as e:
Simon Glassa6b44ac2023-07-24 09:19:59 -06007025 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307026 self.assertIn("Schema validation error", str(e.exception))
Simon Glassefddab62023-01-07 14:07:08 -07007027
Neha Malcom Francis78144822023-07-22 00:14:25 +05307028 def testPackTiSecure(self):
7029 """Test that an image with a TI secured binary can be created"""
7030 keyfile = self.TestFile('key.key')
7031 entry_args = {
7032 'keyfile': keyfile,
7033 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007034 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307035 entry_args=entry_args)[0]
7036 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7037
7038 def testPackTiSecureMissingTool(self):
7039 """Test that an image with a TI secured binary (non-functional) can be created
7040 when openssl is missing"""
7041 keyfile = self.TestFile('key.key')
7042 entry_args = {
7043 'keyfile': keyfile,
7044 }
7045 with test_util.capture_sys_output() as (_, stderr):
Simon Glassa6b44ac2023-07-24 09:19:59 -06007046 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307047 force_missing_bintools='openssl',
7048 entry_args=entry_args)
7049 err = stderr.getvalue()
7050 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7051
7052 def testPackTiSecureROM(self):
7053 """Test that a ROM image with a TI secured binary can be created"""
7054 keyfile = self.TestFile('key.key')
7055 entry_args = {
7056 'keyfile': keyfile,
7057 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007058 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307059 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06007060 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307061 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06007062 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307063 entry_args=entry_args)[0]
7064 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7065 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7066 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7067
7068 def testPackTiSecureROMCombined(self):
7069 """Test that a ROM image with a TI secured binary can be created"""
7070 keyfile = self.TestFile('key.key')
7071 entry_args = {
7072 'keyfile': keyfile,
7073 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007074 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307075 entry_args=entry_args)[0]
7076 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7077
Christian Taedcke289e6002023-07-17 09:05:54 +02007078 def testEncryptedNoAlgo(self):
7079 """Test encrypted node with missing required properties"""
7080 with self.assertRaises(ValueError) as e:
7081 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7082 self.assertIn(
7083 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7084 str(e.exception))
7085
7086 def testEncryptedInvalidIvfile(self):
7087 """Test encrypted node with invalid iv file"""
7088 with self.assertRaises(ValueError) as e:
7089 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7090 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7091 str(e.exception))
7092
7093 def testEncryptedMissingKey(self):
7094 """Test encrypted node with missing key properties"""
7095 with self.assertRaises(ValueError) as e:
7096 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7097 self.assertIn(
7098 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7099 str(e.exception))
7100
7101 def testEncryptedKeySource(self):
7102 """Test encrypted node with key-source property"""
7103 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7104
7105 dtb = fdt.Fdt.FromData(data)
7106 dtb.Scan()
7107
7108 node = dtb.GetNode('/images/u-boot/cipher')
7109 self.assertEqual('algo-name', node.props['algo'].value)
7110 self.assertEqual('key-source-value', node.props['key-source'].value)
7111 self.assertEqual(ENCRYPTED_IV_DATA,
7112 tools.to_bytes(''.join(node.props['iv'].value)))
7113 self.assertNotIn('key', node.props)
7114
7115 def testEncryptedKeyFile(self):
7116 """Test encrypted node with key-filename property"""
7117 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7118
7119 dtb = fdt.Fdt.FromData(data)
7120 dtb.Scan()
7121
7122 node = dtb.GetNode('/images/u-boot/cipher')
7123 self.assertEqual('algo-name', node.props['algo'].value)
7124 self.assertEqual(ENCRYPTED_IV_DATA,
7125 tools.to_bytes(''.join(node.props['iv'].value)))
7126 self.assertEqual(ENCRYPTED_KEY_DATA,
7127 tools.to_bytes(''.join(node.props['key'].value)))
7128 self.assertNotIn('key-source', node.props)
7129
7130
Lukas Funke8c1fbd12023-07-18 13:53:13 +02007131 def testSplPubkeyDtb(self):
7132 """Test u_boot_spl_pubkey_dtb etype"""
7133 data = tools.read_file(self.TestFile("key.pem"))
7134 self._MakeInputFile("key.crt", data)
7135 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7136 image = control.images['image']
7137 entries = image.GetEntries()
7138 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7139 dtb_data = dtb_entry.GetData()
7140 dtb = fdt.Fdt.FromData(dtb_data)
7141 dtb.Scan()
7142
7143 signature_node = dtb.GetNode('/signature')
7144 self.assertIsNotNone(signature_node)
7145 key_node = signature_node.FindNode("key-key")
7146 self.assertIsNotNone(key_node)
7147 self.assertEqual(fdt_util.GetString(key_node, "required"),
7148 "conf")
7149 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7150 "sha384,rsa4096")
7151 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7152 "key")
7153
Lukas Funked8a2d3b2023-08-03 17:22:14 +02007154 def testXilinxBootgenSigning(self):
7155 """Test xilinx-bootgen etype"""
7156 bootgen = bintool.Bintool.create('bootgen')
7157 self._CheckBintool(bootgen)
7158 data = tools.read_file(self.TestFile("key.key"))
7159 self._MakeInputFile("psk.pem", data)
7160 self._MakeInputFile("ssk.pem", data)
7161 self._SetupPmuFwlElf()
7162 self._SetupSplElf()
7163 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7164 image_fname = tools.get_output_filename('image.bin')
7165
7166 # Read partition header table and check if authentication is enabled
7167 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7168 "-read", image_fname, "pht").splitlines()
7169 attributes = {"authentication": None,
7170 "core": None,
7171 "encryption": None}
7172
7173 for l in bootgen_out:
7174 for a in attributes.keys():
7175 if a in l:
7176 m = re.match(fr".*{a} \[([^]]+)\]", l)
7177 attributes[a] = m.group(1)
7178
7179 self.assertTrue(attributes['authentication'] == "rsa")
7180 self.assertTrue(attributes['core'] == "a53-0")
7181 self.assertTrue(attributes['encryption'] == "no")
7182
7183 def testXilinxBootgenSigningEncryption(self):
7184 """Test xilinx-bootgen etype"""
7185 bootgen = bintool.Bintool.create('bootgen')
7186 self._CheckBintool(bootgen)
7187 data = tools.read_file(self.TestFile("key.key"))
7188 self._MakeInputFile("psk.pem", data)
7189 self._MakeInputFile("ssk.pem", data)
7190 self._SetupPmuFwlElf()
7191 self._SetupSplElf()
7192 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7193 image_fname = tools.get_output_filename('image.bin')
7194
7195 # Read boot header in order to verify encryption source and
7196 # encryption parameter
7197 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7198 "-read", image_fname, "bh").splitlines()
7199 attributes = {"auth_only":
7200 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7201 "encryption_keystore":
7202 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7203 "value": None},
7204 }
7205
7206 for l in bootgen_out:
7207 for a in attributes.keys():
7208 if a in l:
7209 m = re.match(attributes[a]['re'], l)
7210 attributes[a] = m.group(1)
7211
7212 # Check if fsbl-attribute is set correctly
7213 self.assertTrue(attributes['auth_only'] == "true")
7214 # Check if key is stored in efuse
7215 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7216
7217 def testXilinxBootgenMissing(self):
7218 """Test that binman still produces an image if bootgen is missing"""
7219 data = tools.read_file(self.TestFile("key.key"))
7220 self._MakeInputFile("psk.pem", data)
7221 self._MakeInputFile("ssk.pem", data)
7222 self._SetupPmuFwlElf()
7223 self._SetupSplElf()
7224 with test_util.capture_sys_output() as (_, stderr):
7225 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7226 force_missing_bintools='bootgen')
7227 err = stderr.getvalue()
7228 self.assertRegex(err,
7229 "Image 'image'.*missing bintools.*: bootgen")
7230
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307231 def _GetCapsuleHeaders(self, data):
7232 """Get the capsule header contents
7233
7234 Args:
7235 data: Capsule file contents
7236
7237 Returns:
7238 Dict:
7239 key: Capsule Header name (str)
7240 value: Header field value (str)
7241 """
7242 capsule_file = os.path.join(self._indir, 'test.capsule')
7243 tools.write_file(capsule_file, data)
7244
7245 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7246 lines = out.splitlines()
7247
7248 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7249 vals = {}
7250 for line in lines:
7251 mat = re_line.match(line)
7252 if mat:
7253 vals[mat.group(1)] = mat.group(2)
7254
7255 return vals
7256
Sughosh Ganub6176112023-08-22 23:09:59 +05307257 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7258 capoemflags=False):
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307259 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7260 fmp_size = "00000010"
7261 fmp_fw_version = "00000002"
7262 capsule_image_index = "00000001"
7263 oemflag = "00018000"
7264 auth_hdr_revision = "00000200"
7265 auth_hdr_cert_type = "00000EF1"
Sughosh Ganub6176112023-08-22 23:09:59 +05307266
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307267 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganub6176112023-08-22 23:09:59 +05307268
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307269 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganub6176112023-08-22 23:09:59 +05307270
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307271 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7272
7273 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7274 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7275 self.assertEqual(capsule_image_index,
7276 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganub6176112023-08-22 23:09:59 +05307277
7278 if capoemflags:
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307279 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7280
7281 if signed_capsule:
7282 self.assertEqual(auth_hdr_revision,
7283 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7284 self.assertEqual(auth_hdr_cert_type,
7285 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7286 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7287 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7288
7289 if version_check:
7290 self.assertEqual(fmp_signature,
7291 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7292 self.assertEqual(fmp_size,
7293 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7294 self.assertEqual(fmp_fw_version,
7295 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7296
7297 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganub6176112023-08-22 23:09:59 +05307298
Sughosh Ganu74aae502023-10-10 14:40:59 +05307299 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7300 if accept_capsule:
7301 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7302 else:
7303 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7304
7305 hdr = self._GetCapsuleHeaders(data)
7306
7307 self.assertEqual(capsule_hdr_guid.upper(),
7308 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7309
7310 if accept_capsule:
7311 capsule_size = "0000002C"
7312 else:
7313 capsule_size = "0000001C"
7314 self.assertEqual(capsule_size,
7315 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7316
7317 if accept_capsule:
7318 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7319
Sughosh Ganub6176112023-08-22 23:09:59 +05307320 def testCapsuleGen(self):
7321 """Test generation of EFI capsule"""
7322 data = self._DoReadFile('311_capsule.dts')
7323
7324 self._CheckCapsule(data)
7325
7326 def testSignedCapsuleGen(self):
7327 """Test generation of EFI capsule"""
7328 data = tools.read_file(self.TestFile("key.key"))
7329 self._MakeInputFile("key.key", data)
7330 data = tools.read_file(self.TestFile("key.pem"))
7331 self._MakeInputFile("key.crt", data)
7332
7333 data = self._DoReadFile('312_capsule_signed.dts')
7334
7335 self._CheckCapsule(data, signed_capsule=True)
7336
7337 def testCapsuleGenVersionSupport(self):
7338 """Test generation of EFI capsule with version support"""
7339 data = self._DoReadFile('313_capsule_version.dts')
7340
7341 self._CheckCapsule(data, version_check=True)
7342
7343 def testCapsuleGenSignedVer(self):
7344 """Test generation of signed EFI capsule with version information"""
7345 data = tools.read_file(self.TestFile("key.key"))
7346 self._MakeInputFile("key.key", data)
7347 data = tools.read_file(self.TestFile("key.pem"))
7348 self._MakeInputFile("key.crt", data)
7349
7350 data = self._DoReadFile('314_capsule_signed_ver.dts')
7351
7352 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7353
7354 def testCapsuleGenCapOemFlags(self):
7355 """Test generation of EFI capsule with OEM Flags set"""
7356 data = self._DoReadFile('315_capsule_oemflags.dts')
7357
7358 self._CheckCapsule(data, capoemflags=True)
7359
7360 def testCapsuleGenKeyMissing(self):
7361 """Test that binman errors out on missing key"""
7362 with self.assertRaises(ValueError) as e:
7363 self._DoReadFile('316_capsule_missing_key.dts')
7364
7365 self.assertIn("Both private key and public key certificate need to be provided",
7366 str(e.exception))
7367
7368 def testCapsuleGenIndexMissing(self):
7369 """Test that binman errors out on missing image index"""
7370 with self.assertRaises(ValueError) as e:
7371 self._DoReadFile('317_capsule_missing_index.dts')
7372
7373 self.assertIn("entry is missing properties: image-index",
7374 str(e.exception))
7375
7376 def testCapsuleGenGuidMissing(self):
7377 """Test that binman errors out on missing image GUID"""
7378 with self.assertRaises(ValueError) as e:
7379 self._DoReadFile('318_capsule_missing_guid.dts')
7380
7381 self.assertIn("entry is missing properties: image-guid",
7382 str(e.exception))
7383
Sughosh Ganu74aae502023-10-10 14:40:59 +05307384 def testCapsuleGenAcceptCapsule(self):
7385 """Test generationg of accept EFI capsule"""
7386 data = self._DoReadFile('319_capsule_accept.dts')
7387
7388 self._CheckEmptyCapsule(data, accept_capsule=True)
7389
7390 def testCapsuleGenRevertCapsule(self):
7391 """Test generationg of revert EFI capsule"""
7392 data = self._DoReadFile('320_capsule_revert.dts')
7393
7394 self._CheckEmptyCapsule(data)
7395
7396 def testCapsuleGenAcceptGuidMissing(self):
7397 """Test that binman errors out on missing image GUID for accept capsule"""
7398 with self.assertRaises(ValueError) as e:
7399 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7400
7401 self.assertIn("Image GUID needed for generating accept capsule",
7402 str(e.exception))
7403
7404 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7405 """Test that capsule-type is specified"""
7406 with self.assertRaises(ValueError) as e:
7407 self._DoReadFile('322_empty_capsule_type_missing.dts')
7408
7409 self.assertIn("entry is missing properties: capsule-type",
7410 str(e.exception))
7411
7412 def testCapsuleGenAcceptOrRevertMissing(self):
7413 """Test that both accept and revert capsule are not specified"""
7414 with self.assertRaises(ValueError) as e:
7415 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7416
Simon Glass9fc60b42017-11-12 21:52:22 -07007417if __name__ == "__main__":
7418 unittest.main()