blob: fa17490001488a297090a65c0c099ecc9a40e0f8 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-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 Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Alice Guo1d334022025-04-28 18:37:39 +0800107IMX_LPDDR_IMEM_DATA = b'qwertyuiop1234567890'
108IMX_LPDDR_DMEM_DATA = b'asdfghjklzxcvbnm'
Simon Glassa435cd12020-09-01 05:13:59 -0600109
110# Subdirectory of the input dir to use to put test FDTs
111TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600112
Simon Glass2c6adba2019-07-20 12:23:47 -0600113# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600114EXTRACT_DTB_SIZE = 0x3c9
115
Simon Glass2c6adba2019-07-20 12:23:47 -0600116# Properties expected to be in the device tree when update_dtb is used
117BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
118
Simon Glassfb30e292019-07-20 12:23:51 -0600119# Extra properties expected to be in the device tree when allow-repack is used
120REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
121
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200122# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200123COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700124
Simon Glassad5cfe12023-01-07 14:07:14 -0700125TEE_ADDR = 0x5678
126
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530128FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530129# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100130CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530131# Windows cert GUID
132WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530133# Empty capsule GUIDs
134EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
135EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530136
Simon Glass57454f42016-11-25 20:15:52 -0700137class TestFunctional(unittest.TestCase):
138 """Functional tests for binman
139
140 Most of these use a sample .dts file to build an image and then check
141 that it looks correct. The sample files are in the test/ subdirectory
142 and are numbered.
143
144 For each entry type a very small test file is created using fixed
145 string contents. This makes it easy to test that things look right, and
146 debug problems.
147
148 In some cases a 'real' file must be used - these are also supplied in
149 the test/ diurectory.
150 """
151 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600152 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700153 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600154 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700155
Simon Glass57454f42016-11-25 20:15:52 -0700156 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600157 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
158 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700159
160 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600161 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700162
163 # Create some test files
164 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
165 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
166 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600167 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700168 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700169 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700170 TestFunctional._MakeInputFile('me.bin', ME_DATA)
171 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600172 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Jagdish Gediya311d4842018-09-03 21:35:08 +0530174 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600175
Simon Glassabab18c2019-08-24 07:22:49 -0600176 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
177 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700178 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600179 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600180 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600181
182 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
183 X86_RESET16_DATA)
184 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
185 X86_RESET16_SPL_DATA)
186 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
187 X86_RESET16_TPL_DATA)
188
Simon Glass57454f42016-11-25 20:15:52 -0700189 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700190 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
191 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600192 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
193 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700194 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
195 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700196 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
197 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700198 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700199 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600200 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600201 TestFunctional._MakeInputDir('devkeys')
202 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600203 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600204 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600205 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600206 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Alice Guo1d334022025-04-28 18:37:39 +0800207 TestFunctional._MakeInputFile('lpddr5_imem.bin', IMX_LPDDR_IMEM_DATA)
208 TestFunctional._MakeInputFile('lpddr5_dmem.bin', IMX_LPDDR_DMEM_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700209
Simon Glassf6290892019-08-24 07:22:53 -0600210 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
211 elf_test.BuildElfTestFiles(cls._elf_testdir)
212
Simon Glass72232452016-11-25 20:15:53 -0700213 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600214 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700215 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700216
217 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600218 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700219
Simon Glass862f8e22019-08-24 07:22:43 -0600220 shutil.copytree(cls.TestFile('files'),
221 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600222
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530223 shutil.copytree(cls.TestFile('yaml'),
224 os.path.join(cls._indir, 'yaml'))
225
Simon Glass7ba33592018-09-14 04:57:26 -0600226 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600227 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600228 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200229 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530230 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700231 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800232 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500233 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000234 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530235 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530236 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600237
Simon Glassa435cd12020-09-01 05:13:59 -0600238 # Add a few .dtb files for testing
239 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
240 TEST_FDT1_DATA)
241 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
242 TEST_FDT2_DATA)
243
Simon Glassa0729502020-09-06 10:35:33 -0600244 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
245
Simon Glass5f423422022-03-05 20:19:12 -0700246 # ELF file with two sections in different parts of memory, used for both
247 # ATF and OP_TEE
248 TestFunctional._MakeInputFile('bl31.elf',
249 tools.read_file(cls.ElfTestFile('elf_sections')))
250 TestFunctional._MakeInputFile('tee.elf',
251 tools.read_file(cls.ElfTestFile('elf_sections')))
252
Simon Glassad5cfe12023-01-07 14:07:14 -0700253 # Newer OP_TEE file in v1 binary format
254 cls.make_tee_bin('tee.bin')
255
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200256 # test files for encrypted tests
257 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
258 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
259
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200260 cls.comp_bintools = {}
261 for name in COMP_BINTOOLS:
262 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600263
Simon Glass57454f42016-11-25 20:15:52 -0700264 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600265 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700266 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600267 if cls.preserve_indir:
268 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600269 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600270 if cls._indir:
271 shutil.rmtree(cls._indir)
272 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700273
Simon Glass1c420c92019-07-08 13:18:49 -0600274 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600275 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600276 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600277 """Accept arguments controlling test execution
278
279 Args:
280 preserve_indir: Preserve the shared input directory used by all
281 tests in this class.
282 preserve_outdir: Preserve the output directories used by tests. Each
283 test has its own, so this is normally only useful when running a
284 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600285 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600286 """
287 cls.preserve_indir = preserve_indir
288 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600289 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600290 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600291
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200292 def _CheckBintool(self, bintool):
293 if not bintool.is_present():
294 self.skipTest('%s not available' % bintool.name)
295
Simon Glass1de34482019-07-08 13:18:53 -0600296 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200297 bintool = self.comp_bintools['lz4']
298 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600299
Simon Glassee9d10d2019-07-20 12:24:09 -0600300 def _CleanupOutputDir(self):
301 """Remove the temporary output directory"""
302 if self.preserve_outdirs:
303 print('Preserving output dir: %s' % tools.outdir)
304 else:
Simon Glass80025522022-01-29 14:14:04 -0700305 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600306
Simon Glass57454f42016-11-25 20:15:52 -0700307 def setUp(self):
308 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700309 # tout.init(tout.DEBUG)
Simon Glass5dc22cf2025-02-03 09:26:42 -0700310 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700311
312 def tearDown(self):
313 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600314 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700315
Simon Glassb3d6fc72019-07-20 12:24:10 -0600316 def _SetupImageInTmpdir(self):
317 """Set up the output image in a new temporary directory
318
319 This is used when an image has been generated in the output directory,
320 but we want to run binman again. This will create a new output
321 directory and fail to delete the original one.
322
323 This creates a new temporary directory, copies the image to it (with a
324 new name) and removes the old output directory.
325
326 Returns:
327 Tuple:
328 Temporary directory to use
329 New image filename
330 """
Simon Glass80025522022-01-29 14:14:04 -0700331 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600332 tmpdir = tempfile.mkdtemp(prefix='binman.')
333 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700334 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600335 self._CleanupOutputDir()
336 return tmpdir, updated_fname
337
Simon Glass8425a1f2018-07-17 13:25:48 -0600338 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600339 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600340 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
341 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
342 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700343 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600344
Simon Glass57454f42016-11-25 20:15:52 -0700345 def _RunBinman(self, *args, **kwargs):
346 """Run binman using the command line
347
348 Args:
349 Arguments to pass, as a list of strings
350 kwargs: Arguments to pass to Command.RunPipe()
351 """
Simon Glass51f55182025-02-03 09:26:45 -0700352 all_args = [self._binman_pathname] + list(args)
353 result = command.run_one(*all_args, capture=True, capture_stderr=True,
354 raise_on_error=False)
Simon Glass57454f42016-11-25 20:15:52 -0700355 if result.return_code and kwargs.get('raise_on_error', True):
356 raise Exception("Error running '%s': %s" % (' '.join(args),
357 result.stdout + result.stderr))
358 return result
359
Simon Glassf46732a2019-07-08 14:25:29 -0600360 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700361 """Run binman using directly (in the same process)
362
363 Args:
364 Arguments to pass, as a list of strings
365 Returns:
366 Return value (0 for success)
367 """
Simon Glassf46732a2019-07-08 14:25:29 -0600368 argv = list(argv)
369 args = cmdline.ParseArgs(argv)
370 args.pager = 'binman-invalid-pager'
371 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700372
373 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600374 # args.verbosity = tout.DEBUG
375 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700376
Simon Glass91710b32018-07-17 13:25:32 -0600377 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600378 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300379 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100380 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700381 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530382 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700383 """Run binman with a given test file
384
385 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600386 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600387 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600388 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600389 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600390 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600391 entry_args: Dict of entry args to supply to binman
392 key: arg name
393 value: value of that arg
394 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600395 use_real_dtb: True to use the test file as the contents of
396 the u-boot-dtb entry. Normally this is not needed and the
397 test contents (the U_BOOT_DTB_DATA string) can be used.
398 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300399 use_expanded: True to use expanded entries where available, e.g.
400 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600401 verbosity: Verbosity level to use (0-3, None=don't set it)
402 allow_missing: Set the '--allow-missing' flag so that missing
403 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100404 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600405 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600406 threads: Number of threads to use (None for default, 0 for
407 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600408 test_section_timeout: True to force the first time to timeout, as
409 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600410 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600411 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700412 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600413 ignore_missing (bool): True to return success even if there are
414 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530415 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600416
417 Returns:
418 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700419 """
Simon Glassf46732a2019-07-08 14:25:29 -0600420 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700421 if debug:
422 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600423 if verbosity is not None:
424 args.append('-v%d' % verbosity)
425 elif self.verbosity:
426 args.append('-v%d' % self.verbosity)
427 if self.toolpath:
428 for path in self.toolpath:
429 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600430 if threads is not None:
431 args.append('-T%d' % threads)
432 if test_section_timeout:
433 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600434 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600435 if map:
436 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600437 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600438 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600439 if not use_real_dtb:
440 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300441 if not use_expanded:
442 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600443 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600444 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600445 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600446 if allow_missing:
447 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700448 if ignore_missing:
449 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100450 if allow_fake_blobs:
451 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700452 if force_missing_bintools:
453 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600454 if update_fdt_in_elf:
455 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600456 if images:
457 for image in images:
458 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600459 if extra_indirs:
460 for indir in extra_indirs:
461 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530462 if output_dir:
463 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700464 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700465
466 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700467 """Set up a new test device-tree file
468
469 The given file is compiled and set up as the device tree to be used
470 for ths test.
471
472 Args:
473 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600474 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700475
476 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600477 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700478 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600479 tmpdir = tempfile.mkdtemp(prefix='binmant.')
480 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600481 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700482 data = fd.read()
483 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600484 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600485 return data
Simon Glass57454f42016-11-25 20:15:52 -0700486
Simon Glass56d05412022-02-28 07:16:54 -0700487 def _GetDtbContentsForSpls(self, dtb_data, name):
488 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600489
490 For testing we don't actually have different versions of the DTB. With
491 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
492 we don't normally have any unwanted nodes.
493
494 We still want the DTBs for SPL and TPL to be different though, since
495 otherwise it is confusing to know which one we are looking at. So add
496 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600497
498 Args:
499 dtb_data: dtb data to modify (this should be a value devicetree)
500 name: Name of a new property to add
501
502 Returns:
503 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600504 """
505 dtb = fdt.Fdt.FromData(dtb_data)
506 dtb.Scan()
507 dtb.GetNode('/binman').AddZeroProp(name)
508 dtb.Sync(auto_resize=True)
509 dtb.Pack()
510 return dtb.GetContents()
511
Simon Glassed930672021-03-18 20:25:05 +1300512 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600513 verbosity=None, map=False, update_dtb=False,
514 entry_args=None, reset_dtbs=True, extra_indirs=None,
515 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700516 """Run binman and return the resulting image
517
518 This runs binman with a given test file and then reads the resulting
519 output file. It is a shortcut function since most tests need to do
520 these steps.
521
522 Raises an assertion failure if binman returns a non-zero exit code.
523
524 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600525 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700526 use_real_dtb: True to use the test file as the contents of
527 the u-boot-dtb entry. Normally this is not needed and the
528 test contents (the U_BOOT_DTB_DATA string) can be used.
529 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300530 use_expanded: True to use expanded entries where available, e.g.
531 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600532 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600533 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600534 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600535 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600536 entry_args: Dict of entry args to supply to binman
537 key: arg name
538 value: value of that arg
539 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
540 function. If reset_dtbs is True, then the original test dtb
541 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600542 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600543 threads: Number of threads to use (None for default, 0 for
544 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700545
546 Returns:
547 Tuple:
548 Resulting image contents
549 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600550 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600551 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700552 """
Simon Glass72232452016-11-25 20:15:53 -0700553 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700554 # Use the compiled test file as the u-boot-dtb input
555 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700556 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600557
558 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100559 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700560 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600561 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
562 outfile = os.path.join(self._indir, dtb_fname)
563 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700564 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700565
566 try:
Simon Glass91710b32018-07-17 13:25:32 -0600567 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600568 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600569 use_expanded=use_expanded, verbosity=verbosity,
570 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600571 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700572 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700573 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700574
575 # Find the (only) image, read it and return its contents
576 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700577 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600578 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600579 if map:
Simon Glass80025522022-01-29 14:14:04 -0700580 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600581 with open(map_fname) as fd:
582 map_data = fd.read()
583 else:
584 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600585 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600586 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700587 finally:
588 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600589 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600590 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700591
Simon Glass5b4bce32019-07-08 14:25:26 -0600592 def _DoReadFileRealDtb(self, fname):
593 """Run binman with a real .dtb file and return the resulting data
594
595 Args:
596 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
597
598 Returns:
599 Resulting image contents
600 """
601 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
602
Simon Glass72232452016-11-25 20:15:53 -0700603 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600604 """Helper function which discards the device-tree binary
605
606 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600607 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600608 use_real_dtb: True to use the test file as the contents of
609 the u-boot-dtb entry. Normally this is not needed and the
610 test contents (the U_BOOT_DTB_DATA string) can be used.
611 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600612
613 Returns:
614 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600615 """
Simon Glass72232452016-11-25 20:15:53 -0700616 return self._DoReadFileDtb(fname, use_real_dtb)[0]
617
Simon Glass57454f42016-11-25 20:15:52 -0700618 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600619 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700620 """Create a new test input file, creating directories as needed
621
622 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600623 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700624 contents: File contents to write in to the file
625 Returns:
626 Full pathname of file created
627 """
Simon Glass862f8e22019-08-24 07:22:43 -0600628 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700629 dirname = os.path.dirname(pathname)
630 if dirname and not os.path.exists(dirname):
631 os.makedirs(dirname)
632 with open(pathname, 'wb') as fd:
633 fd.write(contents)
634 return pathname
635
636 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600637 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600638 """Create a new test input directory, creating directories as needed
639
640 Args:
641 dirname: Directory name to create
642
643 Returns:
644 Full pathname of directory created
645 """
Simon Glass862f8e22019-08-24 07:22:43 -0600646 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600647 if not os.path.exists(pathname):
648 os.makedirs(pathname)
649 return pathname
650
651 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600652 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600653 """Set up an ELF file with a '_dt_ucode_base_size' symbol
654
655 Args:
656 Filename of ELF file to use as SPL
657 """
Simon Glass93a806f2019-08-24 07:22:59 -0600658 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700659 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600660
661 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600662 def _SetupTplElf(cls, src_fname='bss_data'):
663 """Set up an ELF file with a '_dt_ucode_base_size' symbol
664
665 Args:
666 Filename of ELF file to use as TPL
667 """
668 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700669 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600670
671 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700672 def _SetupVplElf(cls, src_fname='bss_data'):
673 """Set up an ELF file with a '_dt_ucode_base_size' symbol
674
675 Args:
676 Filename of ELF file to use as VPL
677 """
678 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
679 tools.read_file(cls.ElfTestFile(src_fname)))
680
681 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200682 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
683 """Set up an ELF file with a '_dt_ucode_base_size' symbol
684
685 Args:
686 Filename of ELF file to use as VPL
687 """
688 TestFunctional._MakeInputFile('pmu-firmware.elf',
689 tools.read_file(cls.ElfTestFile(src_fname)))
690
691 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600692 def _SetupDescriptor(cls):
693 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
694 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
695
696 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600697 def TestFile(cls, fname):
698 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700699
Simon Glassf6290892019-08-24 07:22:53 -0600700 @classmethod
701 def ElfTestFile(cls, fname):
702 return os.path.join(cls._elf_testdir, fname)
703
Simon Glassad5cfe12023-01-07 14:07:14 -0700704 @classmethod
705 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
706 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
707 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
708 dummy, paged_sz) + U_BOOT_DATA
709 data += extra_data
710 TestFunctional._MakeInputFile(fname, data)
711
Simon Glass57454f42016-11-25 20:15:52 -0700712 def AssertInList(self, grep_list, target):
713 """Assert that at least one of a list of things is in a target
714
715 Args:
716 grep_list: List of strings to check
717 target: Target string
718 """
719 for grep in grep_list:
720 if grep in target:
721 return
Simon Glass848cdb52019-05-17 22:00:50 -0600722 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700723
724 def CheckNoGaps(self, entries):
725 """Check that all entries fit together without gaps
726
727 Args:
728 entries: List of entries to check
729 """
Simon Glasse8561af2018-08-01 15:22:37 -0600730 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700731 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600732 self.assertEqual(offset, entry.offset)
733 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700734
Simon Glass72232452016-11-25 20:15:53 -0700735 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600736 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700737
738 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600739 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700740
741 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600742 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700743 """
744 return struct.unpack('>L', dtb[4:8])[0]
745
Simon Glass0f621332019-07-08 14:25:27 -0600746 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600747 def AddNode(node, path):
748 if node.name != '/':
749 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600750 for prop in node.props.values():
751 if prop.name in prop_names:
752 prop_path = path + ':' + prop.name
753 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
754 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600755 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600756 AddNode(subnode, path)
757
758 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600759 AddNode(dtb.GetRoot(), '')
760 return tree
761
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000762 def _CheckSign(self, fit, key):
763 try:
764 tools.run('fit_check_sign', '-k', key, '-f', fit)
765 except:
766 self.fail('Expected signed FIT container')
767 return False
768 return True
769
Paul HENRYS5cf82892025-02-24 22:20:55 +0100770 def _CheckPreload(self, image, key, algo="sha256,rsa2048",
771 padding="pkcs-1.5"):
772 try:
773 tools.run('preload_check_sign', '-k', key, '-a', algo, '-p',
774 padding, '-f', image)
775 except:
776 self.fail('Expected image signed with a pre-load')
777 return False
778 return True
779
Simon Glass57454f42016-11-25 20:15:52 -0700780 def testRun(self):
781 """Test a basic run with valid args"""
782 result = self._RunBinman('-h')
783
784 def testFullHelp(self):
785 """Test that the full help is displayed with -H"""
786 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300787 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500788 # Remove possible extraneous strings
789 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
790 gothelp = result.stdout.replace(extra, '')
791 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700792 self.assertEqual(0, len(result.stderr))
793 self.assertEqual(0, result.return_code)
794
795 def testFullHelpInternal(self):
796 """Test that the full help is displayed with -H"""
797 try:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700798 command.TEST_RESULT = command.CommandResult()
Simon Glass57454f42016-11-25 20:15:52 -0700799 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300800 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700801 finally:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700802 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700803
804 def testHelp(self):
805 """Test that the basic help is displayed with -h"""
806 result = self._RunBinman('-h')
807 self.assertTrue(len(result.stdout) > 200)
808 self.assertEqual(0, len(result.stderr))
809 self.assertEqual(0, result.return_code)
810
Simon Glass57454f42016-11-25 20:15:52 -0700811 def testBoard(self):
812 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600813 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700814 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300815 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700816 self.assertEqual(0, result)
817
818 def testNeedBoard(self):
819 """Test that we get an error when no board ius supplied"""
820 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600821 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700822 self.assertIn("Must provide a board to process (use -b <board>)",
823 str(e.exception))
824
825 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600826 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700827 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600828 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700829 # We get one error from libfdt, and a different one from fdtget.
830 self.AssertInList(["Couldn't open blob from 'missing_file'",
831 'No such file or directory'], str(e.exception))
832
833 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600834 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700835
836 Since this is a source file it should be compiled and the error
837 will come from the device-tree compiler (dtc).
838 """
839 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600840 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700841 self.assertIn("FATAL ERROR: Unable to parse input tree",
842 str(e.exception))
843
844 def testMissingNode(self):
845 """Test that a device tree without a 'binman' node generates an error"""
846 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600847 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700848 self.assertIn("does not have a 'binman' node", str(e.exception))
849
850 def testEmpty(self):
851 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600852 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(0, len(result.stderr))
854 self.assertEqual(0, result.return_code)
855
856 def testInvalidEntry(self):
857 """Test that an invalid entry is flagged"""
858 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600859 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600860 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700861 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
862 "'/binman/not-a-valid-type'", str(e.exception))
863
864 def testSimple(self):
865 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600866 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700867 self.assertEqual(U_BOOT_DATA, data)
868
Simon Glass075a45c2017-11-13 18:55:00 -0700869 def testSimpleDebug(self):
870 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600871 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700872
Simon Glass57454f42016-11-25 20:15:52 -0700873 def testDual(self):
874 """Test that we can handle creating two images
875
876 This also tests image padding.
877 """
Simon Glass511f6582018-10-01 12:22:30 -0600878 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700879 self.assertEqual(0, retcode)
880
881 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600882 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700883 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700884 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600885 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700886 data = fd.read()
887 self.assertEqual(U_BOOT_DATA, data)
888
889 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600890 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700891 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700892 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600893 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700894 data = fd.read()
895 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700896 self.assertEqual(tools.get_bytes(0, 3), data[:3])
897 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700898
899 def testBadAlign(self):
900 """Test that an invalid alignment value is detected"""
901 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600902 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700903 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
904 "of two", str(e.exception))
905
906 def testPackSimple(self):
907 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600908 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700909 self.assertEqual(0, retcode)
910 self.assertIn('image', control.images)
911 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600912 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700913 self.assertEqual(5, len(entries))
914
915 # First u-boot
916 self.assertIn('u-boot', entries)
917 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600918 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700919 self.assertEqual(len(U_BOOT_DATA), entry.size)
920
921 # Second u-boot, aligned to 16-byte boundary
922 self.assertIn('u-boot-align', entries)
923 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600924 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700925 self.assertEqual(len(U_BOOT_DATA), entry.size)
926
927 # Third u-boot, size 23 bytes
928 self.assertIn('u-boot-size', entries)
929 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600930 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700931 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
932 self.assertEqual(23, entry.size)
933
934 # Fourth u-boot, placed immediate after the above
935 self.assertIn('u-boot-next', entries)
936 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600937 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700938 self.assertEqual(len(U_BOOT_DATA), entry.size)
939
Simon Glasse8561af2018-08-01 15:22:37 -0600940 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertIn('u-boot-fixed', entries)
942 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600943 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700944 self.assertEqual(len(U_BOOT_DATA), entry.size)
945
Simon Glass39dd2152019-07-08 14:25:47 -0600946 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700947
948 def testPackExtra(self):
949 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600950 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
951 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700952
Simon Glass57454f42016-11-25 20:15:52 -0700953 self.assertIn('image', control.images)
954 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600955 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600956 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700957
Samuel Hollande2574022023-01-21 17:25:16 -0600958 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700959 self.assertIn('u-boot', entries)
960 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600961 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700962 self.assertEqual(3, entry.pad_before)
963 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600964 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700965 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
966 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600967 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700968
969 # Second u-boot has an aligned size, but it has no effect
970 self.assertIn('u-boot-align-size-nop', entries)
971 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600972 self.assertEqual(pos, entry.offset)
973 self.assertEqual(len(U_BOOT_DATA), entry.size)
974 self.assertEqual(U_BOOT_DATA, entry.data)
975 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
976 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700977
978 # Third u-boot has an aligned size too
979 self.assertIn('u-boot-align-size', entries)
980 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600981 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700982 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600983 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700984 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600985 data[pos:pos + entry.size])
986 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700987
988 # Fourth u-boot has an aligned end
989 self.assertIn('u-boot-align-end', entries)
990 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600991 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700992 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600993 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700994 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600995 data[pos:pos + entry.size])
996 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700997
998 # Fifth u-boot immediately afterwards
999 self.assertIn('u-boot-align-both', entries)
1000 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -06001001 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -07001002 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -06001003 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -07001004 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -06001005 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -07001006
Samuel Hollande2574022023-01-21 17:25:16 -06001007 # Sixth u-boot with both minimum size and aligned size
1008 self.assertIn('u-boot-min-size', entries)
1009 entry = entries['u-boot-min-size']
1010 self.assertEqual(128, entry.offset)
1011 self.assertEqual(32, entry.size)
1012 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
1013 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
1014 data[pos:pos + entry.size])
1015
Simon Glass57454f42016-11-25 20:15:52 -07001016 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001017 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001018
Simon Glassafb9caa2020-10-26 17:40:10 -06001019 dtb = fdt.Fdt(out_dtb_fname)
1020 dtb.Scan()
1021 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1022 expected = {
1023 'image-pos': 0,
1024 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001025 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001026
1027 'u-boot:image-pos': 0,
1028 'u-boot:offset': 0,
1029 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1030
1031 'u-boot-align-size-nop:image-pos': 12,
1032 'u-boot-align-size-nop:offset': 12,
1033 'u-boot-align-size-nop:size': 4,
1034
1035 'u-boot-align-size:image-pos': 16,
1036 'u-boot-align-size:offset': 16,
1037 'u-boot-align-size:size': 32,
1038
1039 'u-boot-align-end:image-pos': 48,
1040 'u-boot-align-end:offset': 48,
1041 'u-boot-align-end:size': 16,
1042
1043 'u-boot-align-both:image-pos': 64,
1044 'u-boot-align-both:offset': 64,
1045 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001046
1047 'u-boot-min-size:image-pos': 128,
1048 'u-boot-min-size:offset': 128,
1049 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001050 }
1051 self.assertEqual(expected, props)
1052
Simon Glass57454f42016-11-25 20:15:52 -07001053 def testPackAlignPowerOf2(self):
1054 """Test that invalid entry alignment is detected"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001056 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001057 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1058 "of two", str(e.exception))
1059
1060 def testPackAlignSizePowerOf2(self):
1061 """Test that invalid entry size alignment is detected"""
1062 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001063 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001064 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1065 "power of two", str(e.exception))
1066
1067 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001068 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001069 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001070 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001071 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001072 "align 0x4 (4)", str(e.exception))
1073
1074 def testPackInvalidSizeAlign(self):
1075 """Test that invalid entry size alignment is detected"""
1076 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001077 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001078 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1079 "align-size 0x4 (4)", str(e.exception))
1080
1081 def testPackOverlap(self):
1082 """Test that overlapping regions are detected"""
1083 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001085 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001086 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1087 str(e.exception))
1088
1089 def testPackEntryOverflow(self):
1090 """Test that entries that overflow their size are detected"""
1091 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001092 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001093 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1094 "but entry size is 0x3 (3)", str(e.exception))
1095
1096 def testPackImageOverflow(self):
1097 """Test that entries which overflow the image size are detected"""
1098 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001099 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001100 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001101 "size 0x3 (3)", str(e.exception))
1102
1103 def testPackImageSize(self):
1104 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001105 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001106 self.assertEqual(0, retcode)
1107 self.assertIn('image', control.images)
1108 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001109 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001110
1111 def testPackImageSizeAlign(self):
1112 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001113 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001114 self.assertEqual(0, retcode)
1115 self.assertIn('image', control.images)
1116 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001117 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001118
1119 def testPackInvalidImageAlign(self):
1120 """Test that invalid image alignment is detected"""
1121 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001122 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001123 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001124 "align-size 0x8 (8)", str(e.exception))
1125
Simon Glass2a0fa982022-02-11 13:23:21 -07001126 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001127 """Test that invalid image alignment is detected"""
1128 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001129 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001130 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001131 "two", str(e.exception))
1132
1133 def testImagePadByte(self):
1134 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001135 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001136 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001137 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001138 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001139
1140 def testImageName(self):
1141 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001142 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001143 self.assertEqual(0, retcode)
1144 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001145 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001146 self.assertTrue(os.path.exists(fname))
1147
1148 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001149 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001150 self.assertTrue(os.path.exists(fname))
1151
1152 def testBlobFilename(self):
1153 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001154 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001155 self.assertEqual(BLOB_DATA, data)
1156
1157 def testPackSorted(self):
1158 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001159 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001160 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001161 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1162 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001163
Simon Glasse8561af2018-08-01 15:22:37 -06001164 def testPackZeroOffset(self):
1165 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001166 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001167 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001168 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001169 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001170 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1171 str(e.exception))
1172
1173 def testPackUbootDtb(self):
1174 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001175 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001176 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001177
1178 def testPackX86RomNoSize(self):
1179 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001180 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001181 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001182 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001183 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001184 "using end-at-4gb", str(e.exception))
1185
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301186 def test4gbAndSkipAtStartTogether(self):
1187 """Test that the end-at-4gb and skip-at-size property can't be used
1188 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001189 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301190 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001191 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001192 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301193 "'skip-at-start'", str(e.exception))
1194
Simon Glass72232452016-11-25 20:15:53 -07001195 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001196 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001197 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001198 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001199 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001200 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1201 "is outside the section '/binman' starting at "
1202 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001203 str(e.exception))
1204
1205 def testPackX86Rom(self):
1206 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001207 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001208 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001209 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1210 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001211
1212 def testPackX86RomMeNoDesc(self):
1213 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001214 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001215 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001216 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001217 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001218 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1219 str(e.exception))
1220 finally:
1221 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001222
1223 def testPackX86RomBadDesc(self):
1224 """Test that the Intel requires a descriptor entry"""
1225 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001226 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001227 self.assertIn("Node '/binman/intel-me': No offset set with "
1228 "offset-unset: should another entry provide this correct "
1229 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001230
1231 def testPackX86RomMe(self):
1232 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001233 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001234 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001235 if data[:0x1000] != expected_desc:
1236 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001237 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1238
1239 def testPackVga(self):
1240 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001241 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001242 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1243
1244 def testPackStart16(self):
1245 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001246 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001247 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1248
Jagdish Gediya311d4842018-09-03 21:35:08 +05301249 def testPackPowerpcMpc85xxBootpgResetvec(self):
1250 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1251 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001252 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301253 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1254
Simon Glass6ba679c2018-07-06 10:27:17 -06001255 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001256 """Handle running a test for insertion of microcode
1257
1258 Args:
1259 dts_fname: Name of test .dts file
1260 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001261 ucode_second: True if the microsecond entry is second instead of
1262 third
Simon Glass820af1d2018-07-06 10:27:16 -06001263
1264 Returns:
1265 Tuple:
1266 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001267 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001268 in the above (two 4-byte words)
1269 """
Simon Glass3d274232017-11-12 21:52:27 -07001270 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001271
1272 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001273 if ucode_second:
1274 ucode_content = data[len(nodtb_data):]
1275 ucode_pos = len(nodtb_data)
1276 dtb_with_ucode = ucode_content[16:]
1277 fdt_len = self.GetFdtLen(dtb_with_ucode)
1278 else:
1279 dtb_with_ucode = data[len(nodtb_data):]
1280 fdt_len = self.GetFdtLen(dtb_with_ucode)
1281 ucode_content = dtb_with_ucode[fdt_len:]
1282 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001283 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001284 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001285 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001286 dtb = fdt.FdtScan(fname)
1287 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001288 self.assertTrue(ucode)
1289 for node in ucode.subnodes:
1290 self.assertFalse(node.props.get('data'))
1291
Simon Glass72232452016-11-25 20:15:53 -07001292 # Check that the microcode appears immediately after the Fdt
1293 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001294 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001295 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1296 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001297 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001298
1299 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001300 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001301 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1302 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001303 u_boot = data[:len(nodtb_data)]
1304 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001305
1306 def testPackUbootMicrocode(self):
1307 """Test that x86 microcode can be handled correctly
1308
1309 We expect to see the following in the image, in order:
1310 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1311 place
1312 u-boot.dtb with the microcode removed
1313 the microcode
1314 """
Simon Glass511f6582018-10-01 12:22:30 -06001315 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001316 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001317 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1318 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001319
Simon Glassbac25c82017-05-27 07:38:26 -06001320 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001321 """Test that x86 microcode can be handled correctly
1322
1323 We expect to see the following in the image, in order:
1324 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1325 place
1326 u-boot.dtb with the microcode
1327 an empty microcode region
1328 """
1329 # We need the libfdt library to run this test since only that allows
1330 # finding the offset of a property. This is required by
1331 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001332 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001333
1334 second = data[len(U_BOOT_NODTB_DATA):]
1335
1336 fdt_len = self.GetFdtLen(second)
1337 third = second[fdt_len:]
1338 second = second[:fdt_len]
1339
Simon Glassbac25c82017-05-27 07:38:26 -06001340 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1341 self.assertIn(ucode_data, second)
1342 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001343
Simon Glassbac25c82017-05-27 07:38:26 -06001344 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001345 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001346 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1347 len(ucode_data))
1348 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001349 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1350 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001351
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001352 def testPackUbootSingleMicrocode(self):
1353 """Test that x86 microcode can be handled correctly with fdt_normal.
1354 """
Simon Glassbac25c82017-05-27 07:38:26 -06001355 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001356
Simon Glass996021e2016-11-25 20:15:54 -07001357 def testUBootImg(self):
1358 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001359 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001360 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001361
1362 def testNoMicrocode(self):
1363 """Test that a missing microcode region is detected"""
1364 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001365 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001366 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1367 "node found in ", str(e.exception))
1368
1369 def testMicrocodeWithoutNode(self):
1370 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1371 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001372 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001373 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1374 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1375
1376 def testMicrocodeWithoutNode2(self):
1377 """Test that a missing u-boot-ucode node is detected"""
1378 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001379 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001380 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1381 "microcode region u-boot-ucode", str(e.exception))
1382
1383 def testMicrocodeWithoutPtrInElf(self):
1384 """Test that a U-Boot binary without the microcode symbol is detected"""
1385 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001386 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001387 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001388 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001389
1390 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001391 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001392 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1393 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1394
1395 finally:
1396 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001397 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001398 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001399
1400 def testMicrocodeNotInImage(self):
1401 """Test that microcode must be placed within the image"""
1402 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001403 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001404 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1405 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001406 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001407
1408 def testWithoutMicrocode(self):
1409 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001410 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001411 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001412 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001413
1414 # Now check the device tree has no microcode
1415 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1416 second = data[len(U_BOOT_NODTB_DATA):]
1417
1418 fdt_len = self.GetFdtLen(second)
1419 self.assertEqual(dtb, second[:fdt_len])
1420
1421 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1422 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001423 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001424
1425 def testUnknownPosSize(self):
1426 """Test that microcode must be placed within the image"""
1427 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001428 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001429 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001430 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001431
1432 def testPackFsp(self):
1433 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001434 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001435 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1436
1437 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001438 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001439 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001440 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001441
1442 def testPackVbt(self):
1443 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001444 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001445 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001446
Simon Glass7f94e832017-11-12 21:52:25 -07001447 def testSplBssPad(self):
1448 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001449 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001450 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001451 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001452 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001453 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001454
Simon Glass04cda032018-10-01 21:12:42 -06001455 def testSplBssPadMissing(self):
1456 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001457 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001458 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001459 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001460 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1461 str(e.exception))
1462
Simon Glasse83679d2017-11-12 21:52:26 -07001463 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001464 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001465 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001466 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1467
Simon Glass6ba679c2018-07-06 10:27:17 -06001468 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1469 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001470
1471 We expect to see the following in the image, in order:
1472 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1473 correct place
1474 u-boot.dtb with the microcode removed
1475 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001476
1477 Args:
1478 dts: Device tree file to use for test
1479 ucode_second: True if the microsecond entry is second instead of
1480 third
Simon Glass3d274232017-11-12 21:52:27 -07001481 """
Simon Glass7057d022018-10-01 21:12:47 -06001482 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001483 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1484 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001485 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1486 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001487
Simon Glass6ba679c2018-07-06 10:27:17 -06001488 def testPackUbootSplMicrocode(self):
1489 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001490 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001491 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001492
1493 def testPackUbootSplMicrocodeReorder(self):
1494 """Test that order doesn't matter for microcode entries
1495
1496 This is the same as testPackUbootSplMicrocode but when we process the
1497 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1498 entry, so we reply on binman to try later.
1499 """
Simon Glass511f6582018-10-01 12:22:30 -06001500 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001501 ucode_second=True)
1502
Simon Glassa409c932017-11-12 21:52:28 -07001503 def testPackMrc(self):
1504 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001505 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001506 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1507
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001508 def testSplDtb(self):
1509 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001510 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001511 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001512 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1513
Simon Glass0a6da312017-11-13 18:54:56 -07001514 def testSplNoDtb(self):
1515 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001516 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001517 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001518 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1519
Simon Glass7098b7f2021-03-21 18:24:30 +13001520 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001521 use_expanded=False, no_write_symbols=False,
1522 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001523 """Check the image contains the expected symbol values
1524
1525 Args:
1526 dts: Device tree file to use for test
1527 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001528 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1529 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001530 entry_args: Dict of entry args to supply to binman
1531 key: arg name
1532 value: value of that arg
1533 use_expanded: True to use expanded entries where available, e.g.
1534 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001535 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1536 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001537 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001538 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001539 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1540 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001541 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001542 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001543 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001544
Simon Glass7057d022018-10-01 21:12:47 -06001545 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001546 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001547 use_expanded=use_expanded,
1548 verbosity=None if u_boot_offset else 3)[0]
1549
1550 # The lz4-compressed version of the U-Boot data is 19 bytes long
1551 comp_uboot_len = 19
1552
Simon Glass31e04cb2021-03-18 20:24:56 +13001553 # The image should contain the symbols from u_boot_binman_syms.c
1554 # Note that image_pos is adjusted by the base address of the image,
1555 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001556 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001557 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001558 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1559 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1560 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001561
1562 # u-boot-spl has a symbols-base property, so take that into account if
1563 # required. The caller must supply the value
1564 vals = list(vals2)
1565 if symbols_base is not None:
1566 vals[3] = symbols_base + u_boot_offset
1567 vals = tuple(vals)
1568
Simon Glass4b4049e2024-08-26 13:11:39 -06001569 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001570 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001571 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001572 self.assertEqual(
1573 base_data +
1574 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1575 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001576 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001577 got_vals = struct.unpack('<LLQLL', data[:24])
1578
1579 # For debugging:
1580 #print('expect:', list(f'{v:x}' for v in vals))
1581 #print(' got:', list(f'{v:x}' for v in got_vals))
1582
1583 self.assertEqual(vals, got_vals)
1584 self.assertEqual(sym_values, data[:24])
1585
1586 blen = len(base_data)
1587 self.assertEqual(base_data[24:], data[24:blen])
1588 self.assertEqual(0xff, data[blen])
1589
Simon Glass3eb30a42024-08-26 13:11:42 -06001590 if u_boot_offset:
1591 ofs = blen + 1 + len(U_BOOT_DATA)
1592 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1593 else:
1594 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001595
Simon Glass4b0f4142024-08-26 13:11:40 -06001596 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001597 self.assertEqual(base_data[24:], data[ofs + 24:])
1598
1599 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001600 if u_boot_offset:
1601 expected = (sym_values + base_data[24:] +
1602 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1603 sym_values2 + base_data[24:])
1604 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001605
Simon Glass31e04cb2021-03-18 20:24:56 +13001606 def testSymbols(self):
1607 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001608 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001609
1610 def testSymbolsNoDtb(self):
1611 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001612 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001613 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1614 0x38)
1615
Simon Glasse76a3e62018-06-01 09:38:11 -06001616 def testPackUnitAddress(self):
1617 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001618 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001619 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1620
Simon Glassa91e1152018-06-01 09:38:16 -06001621 def testSections(self):
1622 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001623 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001624 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1625 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1626 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001627 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001628
Simon Glass30732662018-06-01 09:38:20 -06001629 def testMap(self):
1630 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001631 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001632 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700163300000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163400000000 00000000 00000010 section@0
163500000000 00000000 00000004 u-boot
163600000010 00000010 00000010 section@1
163700000010 00000000 00000004 u-boot
163800000020 00000020 00000004 section@2
163900000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001640''', map_data)
1641
Simon Glass3b78d532018-06-01 09:38:21 -06001642 def testNamePrefix(self):
1643 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001644 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001645 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700164600000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600164700000000 00000000 00000010 section@0
164800000000 00000000 00000004 ro-u-boot
164900000010 00000010 00000010 section@1
165000000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001651''', map_data)
1652
Simon Glass6ba679c2018-07-06 10:27:17 -06001653 def testUnknownContents(self):
1654 """Test that obtaining the contents works as expected"""
1655 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001656 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001657 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001658 "processing of contents: remaining ["
1659 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001660
Simon Glass2e1169f2018-07-06 10:27:19 -06001661 def testBadChangeSize(self):
1662 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001663 try:
1664 state.SetAllowEntryExpansion(False)
1665 with self.assertRaises(ValueError) as e:
1666 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001667 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001668 str(e.exception))
1669 finally:
1670 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001671
Simon Glassa87014e2018-07-06 10:27:42 -06001672 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001673 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001674 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001675 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001676 dtb = fdt.Fdt(out_dtb_fname)
1677 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001678 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001679 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001680 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001681 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001682 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001683 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001684 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001685 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001686 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001687 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001688 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001689 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001690 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001691
Simon Glasse8561af2018-08-01 15:22:37 -06001692 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001693 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001694 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001695 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001696 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001697 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001698 'size': 40
1699 }, props)
1700
1701 def testUpdateFdtBad(self):
1702 """Test that we detect when ProcessFdt never completes"""
1703 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001704 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001705 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001706 '[<binman.etype._testing.Entry__testing',
1707 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001708
Simon Glass91710b32018-07-17 13:25:32 -06001709 def testEntryArgs(self):
1710 """Test passing arguments to entries from the command line"""
1711 entry_args = {
1712 'test-str-arg': 'test1',
1713 'test-int-arg': '456',
1714 }
Simon Glass511f6582018-10-01 12:22:30 -06001715 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001716 self.assertIn('image', control.images)
1717 entry = control.images['image'].GetEntries()['_testing']
1718 self.assertEqual('test0', entry.test_str_fdt)
1719 self.assertEqual('test1', entry.test_str_arg)
1720 self.assertEqual(123, entry.test_int_fdt)
1721 self.assertEqual(456, entry.test_int_arg)
1722
1723 def testEntryArgsMissing(self):
1724 """Test missing arguments and properties"""
1725 entry_args = {
1726 'test-int-arg': '456',
1727 }
Simon Glass511f6582018-10-01 12:22:30 -06001728 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001729 entry = control.images['image'].GetEntries()['_testing']
1730 self.assertEqual('test0', entry.test_str_fdt)
1731 self.assertEqual(None, entry.test_str_arg)
1732 self.assertEqual(None, entry.test_int_fdt)
1733 self.assertEqual(456, entry.test_int_arg)
1734
1735 def testEntryArgsRequired(self):
1736 """Test missing arguments and properties"""
1737 entry_args = {
1738 'test-int-arg': '456',
1739 }
1740 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001741 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001742 self.assertIn("Node '/binman/_testing': "
1743 'Missing required properties/entry args: test-str-arg, '
1744 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001745 str(e.exception))
1746
1747 def testEntryArgsInvalidFormat(self):
1748 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001749 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1750 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001751 with self.assertRaises(ValueError) as e:
1752 self._DoBinman(*args)
1753 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1754
1755 def testEntryArgsInvalidInteger(self):
1756 """Test that an invalid entry-argument integer is detected"""
1757 entry_args = {
1758 'test-int-arg': 'abc',
1759 }
1760 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001761 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001762 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1763 "'test-int-arg' (value 'abc') to integer",
1764 str(e.exception))
1765
1766 def testEntryArgsInvalidDatatype(self):
1767 """Test that an invalid entry-argument datatype is detected
1768
1769 This test could be written in entry_test.py except that it needs
1770 access to control.entry_args, which seems more than that module should
1771 be able to see.
1772 """
1773 entry_args = {
1774 'test-bad-datatype-arg': '12',
1775 }
1776 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001777 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001778 entry_args=entry_args)
1779 self.assertIn('GetArg() internal error: Unknown data type ',
1780 str(e.exception))
1781
Simon Glass2ca52032018-07-17 13:25:33 -06001782 def testText(self):
1783 """Test for a text entry type"""
1784 entry_args = {
1785 'test-id': TEXT_DATA,
1786 'test-id2': TEXT_DATA2,
1787 'test-id3': TEXT_DATA3,
1788 }
Simon Glass511f6582018-10-01 12:22:30 -06001789 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001790 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001791 expected = (tools.to_bytes(TEXT_DATA) +
1792 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1793 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001794 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001795 self.assertEqual(expected, data)
1796
Simon Glass969616c2018-07-17 13:25:36 -06001797 def testEntryDocs(self):
1798 """Test for creation of entry documentation"""
1799 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001800 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001801 self.assertTrue(len(stdout.getvalue()) > 0)
1802
1803 def testEntryDocsMissing(self):
1804 """Test handling of missing entry documentation"""
1805 with self.assertRaises(ValueError) as e:
1806 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001807 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001808 self.assertIn('Documentation is missing for modules: u_boot',
1809 str(e.exception))
1810
Simon Glass704784b2018-07-17 13:25:38 -06001811 def testFmap(self):
1812 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001813 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001814 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001815 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1816 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001817 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001818 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001819 self.assertEqual(1, fhdr.ver_major)
1820 self.assertEqual(0, fhdr.ver_minor)
1821 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001822 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001823 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001824 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001825 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001826 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001827
Simon Glass82059c22021-04-03 11:05:09 +13001828 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001829 self.assertEqual(b'SECTION0', fentry.name)
1830 self.assertEqual(0, fentry.offset)
1831 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001832 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001833
1834 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001835 self.assertEqual(b'RO_U_BOOT', fentry.name)
1836 self.assertEqual(0, fentry.offset)
1837 self.assertEqual(4, fentry.size)
1838 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001839
Simon Glass82059c22021-04-03 11:05:09 +13001840 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001841 self.assertEqual(b'SECTION1', fentry.name)
1842 self.assertEqual(16, fentry.offset)
1843 self.assertEqual(16, fentry.size)
1844 self.assertEqual(0, fentry.flags)
1845
1846 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001847 self.assertEqual(b'RW_U_BOOT', fentry.name)
1848 self.assertEqual(16, fentry.offset)
1849 self.assertEqual(4, fentry.size)
1850 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001851
Simon Glass82059c22021-04-03 11:05:09 +13001852 fentry = next(fiter)
1853 self.assertEqual(b'FMAP', fentry.name)
1854 self.assertEqual(32, fentry.offset)
1855 self.assertEqual(expect_size, fentry.size)
1856 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001857
Simon Glassdb168d42018-07-17 13:25:39 -06001858 def testBlobNamedByArg(self):
1859 """Test we can add a blob with the filename coming from an entry arg"""
1860 entry_args = {
1861 'cros-ec-rw-path': 'ecrw.bin',
1862 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001863 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001864
Simon Glass53f53992018-07-17 13:25:40 -06001865 def testFill(self):
1866 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001867 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001868 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001869 self.assertEqual(expected, data)
1870
1871 def testFillNoSize(self):
1872 """Test for an fill entry type with no size"""
1873 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001874 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001875 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001876 str(e.exception))
1877
Simon Glassc1ae83c2018-07-17 13:25:44 -06001878 def _HandleGbbCommand(self, pipe_list):
1879 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001880 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001881 fname = pipe_list[0][-1]
1882 # Append our GBB data to the file, which will happen every time the
1883 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001884 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001885 fd.write(GBB_DATA)
1886 return command.CommandResult()
1887
1888 def testGbb(self):
1889 """Test for the Chromium OS Google Binary Block"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07001890 command.TEST_RESULT = self._HandleGbbCommand
Simon Glassc1ae83c2018-07-17 13:25:44 -06001891 entry_args = {
1892 'keydir': 'devkeys',
1893 'bmpblk': 'bmpblk.bin',
1894 }
Simon Glass511f6582018-10-01 12:22:30 -06001895 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001896
1897 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001898 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1899 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001900 self.assertEqual(expected, data)
1901
1902 def testGbbTooSmall(self):
1903 """Test for the Chromium OS Google Binary Block being large enough"""
1904 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001905 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001906 self.assertIn("Node '/binman/gbb': GBB is too small",
1907 str(e.exception))
1908
1909 def testGbbNoSize(self):
1910 """Test for the Chromium OS Google Binary Block having a size"""
1911 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001912 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001913 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1914 str(e.exception))
1915
Simon Glass66152ce2022-01-09 20:14:09 -07001916 def testGbbMissing(self):
1917 """Test that binman still produces an image if futility is missing"""
1918 entry_args = {
1919 'keydir': 'devkeys',
1920 }
1921 with test_util.capture_sys_output() as (_, stderr):
1922 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1923 entry_args=entry_args)
1924 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001925 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001926
Simon Glass5c350162018-07-17 13:25:47 -06001927 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001928 """Fake calls to the futility utility
1929
1930 The expected pipe is:
1931
1932 [('futility', 'vbutil_firmware', '--vblock',
1933 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1934 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1935 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1936 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1937
1938 This writes to the output file (here, 'vblock.vblock'). If
1939 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1940 of the input data (here, 'input.vblock').
1941 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001942 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001943 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001944 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001945 if self._hash_data:
1946 infile = pipe_list[0][11]
1947 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001948 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001949 m.update(data)
1950 fd.write(m.digest())
1951 else:
1952 fd.write(VBLOCK_DATA)
1953
Simon Glass5c350162018-07-17 13:25:47 -06001954 return command.CommandResult()
1955
1956 def testVblock(self):
1957 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001958 self._hash_data = False
Simon Glass5dc22cf2025-02-03 09:26:42 -07001959 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass5c350162018-07-17 13:25:47 -06001960 entry_args = {
1961 'keydir': 'devkeys',
1962 }
Simon Glass511f6582018-10-01 12:22:30 -06001963 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001964 entry_args=entry_args)
1965 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1966 self.assertEqual(expected, data)
1967
1968 def testVblockNoContent(self):
1969 """Test we detect a vblock which has no content to sign"""
1970 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001971 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001972 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001973 'property', str(e.exception))
1974
1975 def testVblockBadPhandle(self):
1976 """Test that we detect a vblock with an invalid phandle in contents"""
1977 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001978 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001979 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1980 '1000', str(e.exception))
1981
1982 def testVblockBadEntry(self):
1983 """Test that we detect an entry that points to a non-entry"""
1984 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001985 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001986 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1987 "'other'", str(e.exception))
1988
Simon Glass220c6222021-01-06 21:35:17 -07001989 def testVblockContent(self):
1990 """Test that the vblock signs the right data"""
1991 self._hash_data = True
Simon Glass5dc22cf2025-02-03 09:26:42 -07001992 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass220c6222021-01-06 21:35:17 -07001993 entry_args = {
1994 'keydir': 'devkeys',
1995 }
1996 data = self._DoReadFileDtb(
1997 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1998 entry_args=entry_args)[0]
1999 hashlen = 32 # SHA256 hash is 32 bytes
2000 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2001 hashval = data[-hashlen:]
2002 dtb = data[len(U_BOOT_DATA):-hashlen]
2003
2004 expected_data = U_BOOT_DATA + dtb
2005
2006 # The hashval should be a hash of the dtb
2007 m = hashlib.sha256()
2008 m.update(expected_data)
2009 expected_hashval = m.digest()
2010 self.assertEqual(expected_hashval, hashval)
2011
Simon Glass66152ce2022-01-09 20:14:09 -07002012 def testVblockMissing(self):
2013 """Test that binman still produces an image if futility is missing"""
2014 entry_args = {
2015 'keydir': 'devkeys',
2016 }
2017 with test_util.capture_sys_output() as (_, stderr):
2018 self._DoTestFile('074_vblock.dts',
2019 force_missing_bintools='futility',
2020 entry_args=entry_args)
2021 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002022 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002023
Simon Glass8425a1f2018-07-17 13:25:48 -06002024 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002025 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002026 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002027 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002028 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002029 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2030
Simon Glass24b97442018-07-17 13:25:51 -06002031 def testUsesPos(self):
2032 """Test that the 'pos' property cannot be used anymore"""
2033 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002034 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002035 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2036 "'pos'", str(e.exception))
2037
Simon Glass274bf092018-09-14 04:57:08 -06002038 def testFillZero(self):
2039 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002040 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002041 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002042
Simon Glass267de432018-09-14 04:57:09 -06002043 def testTextMissing(self):
2044 """Test for a text entry type where there is no text"""
2045 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002046 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002047 self.assertIn("Node '/binman/text': No value provided for text label "
2048 "'test-id'", str(e.exception))
2049
Simon Glassed40e962018-09-14 04:57:10 -06002050 def testPackStart16Tpl(self):
2051 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002052 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002053 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2054
Simon Glass3b376c32018-09-14 04:57:12 -06002055 def testSelectImage(self):
2056 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002057 expected = 'Skipping images: image1'
2058
2059 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002060 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002061 with test_util.capture_sys_output() as (stdout, stderr):
2062 retcode = self._DoTestFile('006_dual_image.dts',
2063 verbosity=verbosity,
2064 images=['image2'])
2065 self.assertEqual(0, retcode)
2066 if verbosity:
2067 self.assertIn(expected, stdout.getvalue())
2068 else:
2069 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002070
Simon Glass80025522022-01-29 14:14:04 -07002071 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2072 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002073 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002074
Simon Glasse219aa42018-09-14 04:57:24 -06002075 def testUpdateFdtAll(self):
2076 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002077 self._SetupSplElf()
2078 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002079 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002080
2081 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002082 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002083 'image-pos': 0,
2084 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002085 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002086 'section:image-pos': 0,
2087 'section:size': 565,
2088 'section/u-boot-dtb:offset': 0,
2089 'section/u-boot-dtb:image-pos': 0,
2090 'section/u-boot-dtb:size': 565,
2091 'u-boot-spl-dtb:offset': 565,
2092 'u-boot-spl-dtb:image-pos': 565,
2093 'u-boot-spl-dtb:size': 585,
2094 'u-boot-tpl-dtb:offset': 1150,
2095 'u-boot-tpl-dtb:image-pos': 1150,
2096 'u-boot-tpl-dtb:size': 585,
2097 'u-boot-vpl-dtb:image-pos': 1735,
2098 'u-boot-vpl-dtb:offset': 1735,
2099 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002100 }
2101
2102 # We expect three device-tree files in the output, one after the other.
2103 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2104 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2105 # main U-Boot tree. All three should have the same postions and offset.
2106 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002107 self.maxDiff = None
2108 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002109 dtb = fdt.Fdt.FromData(data[start:])
2110 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002111 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002112 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002113 expected = dict(base_expected)
2114 if item:
2115 expected[item] = 0
2116 self.assertEqual(expected, props)
2117 start += dtb._fdt_obj.totalsize()
2118
2119 def testUpdateFdtOutput(self):
2120 """Test that output DTB files are updated"""
2121 try:
Simon Glass511f6582018-10-01 12:22:30 -06002122 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002123 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2124
2125 # Unfortunately, compiling a source file always results in a file
2126 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002127 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002128 # binman as a file called u-boot.dtb. To fix this, copy the file
2129 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002130 start = 0
2131 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002132 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002133 dtb = fdt.Fdt.FromData(data[start:])
2134 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002135 pathname = tools.get_output_filename(os.path.split(fname)[1])
2136 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002137 name = os.path.split(fname)[0]
2138
2139 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002140 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002141 else:
2142 orig_indata = dtb_data
2143 self.assertNotEqual(outdata, orig_indata,
2144 "Expected output file '%s' be updated" % pathname)
2145 self.assertEqual(outdata, data[start:start + size],
2146 "Expected output file '%s' to match output image" %
2147 pathname)
2148 start += size
2149 finally:
2150 self._ResetDtbs()
2151
Simon Glass7ba33592018-09-14 04:57:26 -06002152 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002153 bintool = self.comp_bintools['lz4']
2154 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002155
2156 def testCompress(self):
2157 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002158 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002159 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002160 use_real_dtb=True, update_dtb=True)
2161 dtb = fdt.Fdt(out_dtb_fname)
2162 dtb.Scan()
2163 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2164 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002165 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002166
2167 # Do a sanity check on various fields
2168 image = control.images['image']
2169 entries = image.GetEntries()
2170 self.assertEqual(1, len(entries))
2171
2172 entry = entries['blob']
2173 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2174 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2175 orig = self._decompress(entry.data)
2176 self.assertEqual(orig, entry.uncomp_data)
2177
Simon Glass72eeff12020-10-26 17:40:16 -06002178 self.assertEqual(image.data, entry.data)
2179
Simon Glass7ba33592018-09-14 04:57:26 -06002180 expected = {
2181 'blob:uncomp-size': len(COMPRESS_DATA),
2182 'blob:size': len(data),
2183 'size': len(data),
2184 }
2185 self.assertEqual(expected, props)
2186
Simon Glassac6328c2018-09-14 04:57:28 -06002187 def testFiles(self):
2188 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002189 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002190 self.assertEqual(FILES_DATA, data)
2191
2192 def testFilesCompress(self):
2193 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002194 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002195 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002196
2197 image = control.images['image']
2198 entries = image.GetEntries()
2199 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002200 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002201
Simon Glass303f62f2019-05-17 22:00:46 -06002202 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002203 for i in range(1, 3):
2204 key = '%d.dat' % i
2205 start = entries[key].image_pos
2206 len = entries[key].size
2207 chunk = data[start:start + len]
2208 orig += self._decompress(chunk)
2209
2210 self.assertEqual(FILES_DATA, orig)
2211
2212 def testFilesMissing(self):
2213 """Test missing files"""
2214 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002215 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002216 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2217 'no files', str(e.exception))
2218
2219 def testFilesNoPattern(self):
2220 """Test missing files"""
2221 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002222 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002223 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2224 str(e.exception))
2225
Simon Glassdd156a42022-03-05 20:18:59 -07002226 def testExtendSize(self):
2227 """Test an extending entry"""
2228 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002229 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002230 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2231 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2232 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2233 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002234 self.assertEqual(expect, data)
2235 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700223600000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600223700000000 00000000 00000008 fill
223800000008 00000008 00000004 u-boot
22390000000c 0000000c 00000004 section
22400000000c 00000000 00000003 intel-mrc
224100000010 00000010 00000004 u-boot2
224200000014 00000014 0000000c section2
224300000014 00000000 00000008 fill
22440000001c 00000008 00000004 u-boot
224500000020 00000020 00000008 fill2
2246''', map_data)
2247
Simon Glassdd156a42022-03-05 20:18:59 -07002248 def testExtendSizeBad(self):
2249 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002250 with test_util.capture_sys_output() as (stdout, stderr):
2251 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002252 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002253 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2254 'expanding entry', str(e.exception))
2255
Simon Glassae7cf032018-09-14 04:57:31 -06002256 def testHash(self):
2257 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002258 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002259 use_real_dtb=True, update_dtb=True)
2260 dtb = fdt.Fdt(out_dtb_fname)
2261 dtb.Scan()
2262 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2263 m = hashlib.sha256()
2264 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002265 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002266
2267 def testHashNoAlgo(self):
2268 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002269 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002270 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2271 'hash node', str(e.exception))
2272
2273 def testHashBadAlgo(self):
2274 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002275 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002276 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002277 str(e.exception))
2278
2279 def testHashSection(self):
2280 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002281 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002282 use_real_dtb=True, update_dtb=True)
2283 dtb = fdt.Fdt(out_dtb_fname)
2284 dtb.Scan()
2285 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2286 m = hashlib.sha256()
2287 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002288 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002289 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002290
Simon Glass3fb4f422018-09-14 04:57:32 -06002291 def testPackUBootTplMicrocode(self):
2292 """Test that x86 microcode can be handled correctly in TPL
2293
2294 We expect to see the following in the image, in order:
2295 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2296 place
2297 u-boot-tpl.dtb with the microcode removed
2298 the microcode
2299 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002300 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002301 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002302 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002303 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2304 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002305
Simon Glassc64aea52018-09-14 04:57:34 -06002306 def testFmapX86(self):
2307 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002308 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002309 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002310 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002311 self.assertEqual(expected, data[:32])
2312 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2313
2314 self.assertEqual(0x100, fhdr.image_size)
Simon Glassed836ac2025-02-26 09:26:17 -07002315 base = (1 << 32) - 0x100
Simon Glassc64aea52018-09-14 04:57:34 -06002316
Simon Glassed836ac2025-02-26 09:26:17 -07002317 self.assertEqual(base, fentries[0].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002318 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002319 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002320
Simon Glassed836ac2025-02-26 09:26:17 -07002321 self.assertEqual(base + 4, fentries[1].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002322 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002323 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002324
Simon Glassed836ac2025-02-26 09:26:17 -07002325 self.assertEqual(base + 32, fentries[2].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002326 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2327 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002328 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002329
2330 def testFmapX86Section(self):
2331 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002332 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002333 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002334 self.assertEqual(expected, data[:32])
2335 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2336
Simon Glassb1d414c2021-04-03 11:05:10 +13002337 self.assertEqual(0x180, fhdr.image_size)
Simon Glassed836ac2025-02-26 09:26:17 -07002338 base = (1 << 32) - 0x180
Simon Glassb1d414c2021-04-03 11:05:10 +13002339 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002340 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002341
Simon Glass82059c22021-04-03 11:05:09 +13002342 fentry = next(fiter)
2343 self.assertEqual(b'U_BOOT', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002344 self.assertEqual(base, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002345 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002346
Simon Glass82059c22021-04-03 11:05:09 +13002347 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002348 self.assertEqual(b'SECTION', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002349 self.assertEqual(base + 4, fentry.offset)
Simon Glassb1d414c2021-04-03 11:05:10 +13002350 self.assertEqual(0x20 + expect_size, fentry.size)
2351
2352 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002353 self.assertEqual(b'INTEL_MRC', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002354 self.assertEqual(base + 4, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002355 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002356
Simon Glass82059c22021-04-03 11:05:09 +13002357 fentry = next(fiter)
2358 self.assertEqual(b'FMAP', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002359 self.assertEqual(base + 36, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002360 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002361
Simon Glassb1714232018-09-14 04:57:35 -06002362 def testElf(self):
2363 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002364 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002365 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002366 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002367 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002368 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002369
Simon Glass0d673792019-07-08 13:18:25 -06002370 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002371 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002372 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002373 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002374 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002375 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002376
Simon Glasscd817d52018-09-14 04:57:36 -06002377 def testPackOverlapMap(self):
2378 """Test that overlapping regions are detected"""
2379 with test_util.capture_sys_output() as (stdout, stderr):
2380 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002381 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002382 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002383 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2384 stdout.getvalue())
2385
2386 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002387 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002388 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002389 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002390 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002391<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002392<none> 00000000 00000004 u-boot
2393<none> 00000003 00000004 u-boot-align
2394''', map_data)
2395
Simon Glass0d673792019-07-08 13:18:25 -06002396 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002397 """Test that an image with an Intel Reference code binary works"""
2398 data = self._DoReadFile('100_intel_refcode.dts')
2399 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2400
Simon Glasseb023b32019-04-25 21:58:39 -06002401 def testSectionOffset(self):
2402 """Tests use of a section with an offset"""
2403 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2404 map=True)
2405 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700240600000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600240700000004 00000004 00000010 section@0
240800000004 00000000 00000004 u-boot
240900000018 00000018 00000010 section@1
241000000018 00000000 00000004 u-boot
24110000002c 0000002c 00000004 section@2
24120000002c 00000000 00000004 u-boot
2413''', map_data)
2414 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002415 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2416 tools.get_bytes(0x21, 12) +
2417 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2418 tools.get_bytes(0x61, 12) +
2419 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2420 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002421
Simon Glass1de34482019-07-08 13:18:53 -06002422 def testCbfsRaw(self):
2423 """Test base handling of a Coreboot Filesystem (CBFS)
2424
2425 The exact contents of the CBFS is verified by similar tests in
2426 cbfs_util_test.py. The tests here merely check that the files added to
2427 the CBFS can be found in the final image.
2428 """
2429 data = self._DoReadFile('102_cbfs_raw.dts')
2430 size = 0xb0
2431
2432 cbfs = cbfs_util.CbfsReader(data)
2433 self.assertEqual(size, cbfs.rom_size)
2434
2435 self.assertIn('u-boot-dtb', cbfs.files)
2436 cfile = cbfs.files['u-boot-dtb']
2437 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2438
2439 def testCbfsArch(self):
2440 """Test on non-x86 architecture"""
2441 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2442 size = 0x100
2443
2444 cbfs = cbfs_util.CbfsReader(data)
2445 self.assertEqual(size, cbfs.rom_size)
2446
2447 self.assertIn('u-boot-dtb', cbfs.files)
2448 cfile = cbfs.files['u-boot-dtb']
2449 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2450
2451 def testCbfsStage(self):
2452 """Tests handling of a Coreboot Filesystem (CBFS)"""
2453 if not elf.ELF_TOOLS:
2454 self.skipTest('Python elftools not available')
2455 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2456 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2457 size = 0xb0
2458
2459 data = self._DoReadFile('104_cbfs_stage.dts')
2460 cbfs = cbfs_util.CbfsReader(data)
2461 self.assertEqual(size, cbfs.rom_size)
2462
2463 self.assertIn('u-boot', cbfs.files)
2464 cfile = cbfs.files['u-boot']
2465 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2466
2467 def testCbfsRawCompress(self):
2468 """Test handling of compressing raw files"""
2469 self._CheckLz4()
2470 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2471 size = 0x140
2472
2473 cbfs = cbfs_util.CbfsReader(data)
2474 self.assertIn('u-boot', cbfs.files)
2475 cfile = cbfs.files['u-boot']
2476 self.assertEqual(COMPRESS_DATA, cfile.data)
2477
2478 def testCbfsBadArch(self):
2479 """Test handling of a bad architecture"""
2480 with self.assertRaises(ValueError) as e:
2481 self._DoReadFile('106_cbfs_bad_arch.dts')
2482 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2483
2484 def testCbfsNoSize(self):
2485 """Test handling of a missing size property"""
2486 with self.assertRaises(ValueError) as e:
2487 self._DoReadFile('107_cbfs_no_size.dts')
2488 self.assertIn('entry must have a size property', str(e.exception))
2489
Simon Glass3e28f4f2021-11-23 11:03:54 -07002490 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002491 """Test handling of a CBFS entry which does not provide contentsy"""
2492 with self.assertRaises(ValueError) as e:
2493 self._DoReadFile('108_cbfs_no_contents.dts')
2494 self.assertIn('Could not complete processing of contents',
2495 str(e.exception))
2496
2497 def testCbfsBadCompress(self):
2498 """Test handling of a bad architecture"""
2499 with self.assertRaises(ValueError) as e:
2500 self._DoReadFile('109_cbfs_bad_compress.dts')
2501 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2502 str(e.exception))
2503
2504 def testCbfsNamedEntries(self):
2505 """Test handling of named entries"""
2506 data = self._DoReadFile('110_cbfs_name.dts')
2507
2508 cbfs = cbfs_util.CbfsReader(data)
2509 self.assertIn('FRED', cbfs.files)
2510 cfile1 = cbfs.files['FRED']
2511 self.assertEqual(U_BOOT_DATA, cfile1.data)
2512
2513 self.assertIn('hello', cbfs.files)
2514 cfile2 = cbfs.files['hello']
2515 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2516
Simon Glass759af872019-07-08 13:18:54 -06002517 def _SetupIfwi(self, fname):
2518 """Set up to run an IFWI test
2519
2520 Args:
2521 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2522 """
2523 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002524 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002525
2526 # Intel Integrated Firmware Image (IFWI) file
2527 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2528 data = fd.read()
2529 TestFunctional._MakeInputFile(fname,data)
2530
2531 def _CheckIfwi(self, data):
2532 """Check that an image with an IFWI contains the correct output
2533
2534 Args:
2535 data: Conents of output file
2536 """
Simon Glass80025522022-01-29 14:14:04 -07002537 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002538 if data[:0x1000] != expected_desc:
2539 self.fail('Expected descriptor binary at start of image')
2540
2541 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002542 image_fname = tools.get_output_filename('image.bin')
2543 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002544 ifwitool = bintool.Bintool.create('ifwitool')
2545 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002546
Simon Glass80025522022-01-29 14:14:04 -07002547 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002548 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002549
2550 def testPackX86RomIfwi(self):
2551 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2552 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002553 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002554 self._CheckIfwi(data)
2555
2556 def testPackX86RomIfwiNoDesc(self):
2557 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2558 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002559 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002560 self._CheckIfwi(data)
2561
2562 def testPackX86RomIfwiNoData(self):
2563 """Test that an x86 ROM with IFWI handles missing data"""
2564 self._SetupIfwi('ifwi.bin')
2565 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002566 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002567 self.assertIn('Could not complete processing of contents',
2568 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002569
Simon Glass66152ce2022-01-09 20:14:09 -07002570 def testIfwiMissing(self):
2571 """Test that binman still produces an image if ifwitool is missing"""
2572 self._SetupIfwi('fitimage.bin')
2573 with test_util.capture_sys_output() as (_, stderr):
2574 self._DoTestFile('111_x86_rom_ifwi.dts',
2575 force_missing_bintools='ifwitool')
2576 err = stderr.getvalue()
2577 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002578 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002579
Simon Glassc2f1aed2019-07-08 13:18:56 -06002580 def testCbfsOffset(self):
2581 """Test a CBFS with files at particular offsets
2582
2583 Like all CFBS tests, this is just checking the logic that calls
2584 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2585 """
2586 data = self._DoReadFile('114_cbfs_offset.dts')
2587 size = 0x200
2588
2589 cbfs = cbfs_util.CbfsReader(data)
2590 self.assertEqual(size, cbfs.rom_size)
2591
2592 self.assertIn('u-boot', cbfs.files)
2593 cfile = cbfs.files['u-boot']
2594 self.assertEqual(U_BOOT_DATA, cfile.data)
2595 self.assertEqual(0x40, cfile.cbfs_offset)
2596
2597 self.assertIn('u-boot-dtb', cbfs.files)
2598 cfile2 = cbfs.files['u-boot-dtb']
2599 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2600 self.assertEqual(0x140, cfile2.cbfs_offset)
2601
Simon Glass0f621332019-07-08 14:25:27 -06002602 def testFdtmap(self):
2603 """Test an FDT map can be inserted in the image"""
2604 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2605 fdtmap_data = data[len(U_BOOT_DATA):]
2606 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002607 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002608 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002609
2610 fdt_data = fdtmap_data[16:]
2611 dtb = fdt.Fdt.FromData(fdt_data)
2612 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002613 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002614 self.assertEqual({
2615 'image-pos': 0,
2616 'offset': 0,
2617 'u-boot:offset': 0,
2618 'u-boot:size': len(U_BOOT_DATA),
2619 'u-boot:image-pos': 0,
2620 'fdtmap:image-pos': 4,
2621 'fdtmap:offset': 4,
2622 'fdtmap:size': len(fdtmap_data),
2623 'size': len(data),
2624 }, props)
2625
2626 def testFdtmapNoMatch(self):
2627 """Check handling of an FDT map when the section cannot be found"""
2628 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2629
2630 # Mangle the section name, which should cause a mismatch between the
2631 # correct FDT path and the one expected by the section
2632 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002633 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002634 entries = image.GetEntries()
2635 fdtmap = entries['fdtmap']
2636 with self.assertRaises(ValueError) as e:
2637 fdtmap._GetFdtmap()
2638 self.assertIn("Cannot locate node for path '/binman-suffix'",
2639 str(e.exception))
2640
Simon Glasscec34ba2019-07-08 14:25:28 -06002641 def testFdtmapHeader(self):
2642 """Test an FDT map and image header can be inserted in the image"""
2643 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2644 fdtmap_pos = len(U_BOOT_DATA)
2645 fdtmap_data = data[fdtmap_pos:]
2646 fdt_data = fdtmap_data[16:]
2647 dtb = fdt.Fdt.FromData(fdt_data)
2648 fdt_size = dtb.GetFdtObj().totalsize()
2649 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002650 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002651 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2652 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2653
2654 def testFdtmapHeaderStart(self):
2655 """Test an image header can be inserted at the image start"""
2656 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2657 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2658 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002659 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002660 offset = struct.unpack('<I', hdr_data[4:])[0]
2661 self.assertEqual(fdtmap_pos, offset)
2662
2663 def testFdtmapHeaderPos(self):
2664 """Test an image header can be inserted at a chosen position"""
2665 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2666 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2667 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002668 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002669 offset = struct.unpack('<I', hdr_data[4:])[0]
2670 self.assertEqual(fdtmap_pos, offset)
2671
2672 def testHeaderMissingFdtmap(self):
2673 """Test an image header requires an fdtmap"""
2674 with self.assertRaises(ValueError) as e:
2675 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2676 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2677 str(e.exception))
2678
2679 def testHeaderNoLocation(self):
2680 """Test an image header with a no specified location is detected"""
2681 with self.assertRaises(ValueError) as e:
2682 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2683 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2684 str(e.exception))
2685
Simon Glasse61b6f62019-07-08 14:25:37 -06002686 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002687 """Test extending an entry after it is packed"""
2688 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002689 self.assertEqual(b'aaa', data[:3])
2690 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2691 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002692
Simon Glassdd156a42022-03-05 20:18:59 -07002693 def testEntryExtendBad(self):
2694 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002695 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002696 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002697 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002698 str(e.exception))
2699
Simon Glassdd156a42022-03-05 20:18:59 -07002700 def testEntryExtendSection(self):
2701 """Test extending an entry within a section after it is packed"""
2702 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002703 self.assertEqual(b'aaa', data[:3])
2704 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2705 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002706
Simon Glass90d29682019-07-08 14:25:38 -06002707 def testCompressDtb(self):
2708 """Test that compress of device-tree files is supported"""
2709 self._CheckLz4()
2710 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2711 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2712 comp_data = data[len(U_BOOT_DATA):]
2713 orig = self._decompress(comp_data)
2714 dtb = fdt.Fdt.FromData(orig)
2715 dtb.Scan()
2716 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2717 expected = {
2718 'u-boot:size': len(U_BOOT_DATA),
2719 'u-boot-dtb:uncomp-size': len(orig),
2720 'u-boot-dtb:size': len(comp_data),
2721 'size': len(data),
2722 }
2723 self.assertEqual(expected, props)
2724
Simon Glass151bbbf2019-07-08 14:25:41 -06002725 def testCbfsUpdateFdt(self):
2726 """Test that we can update the device tree with CBFS offset/size info"""
2727 self._CheckLz4()
2728 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2729 update_dtb=True)
2730 dtb = fdt.Fdt(out_dtb_fname)
2731 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002732 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002733 del props['cbfs/u-boot:size']
2734 self.assertEqual({
2735 'offset': 0,
2736 'size': len(data),
2737 'image-pos': 0,
2738 'cbfs:offset': 0,
2739 'cbfs:size': len(data),
2740 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002741 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002742 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002743 'cbfs/u-boot:image-pos': 0x30,
2744 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002745 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002746 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002747 }, props)
2748
Simon Glass3c9b4f22019-07-08 14:25:42 -06002749 def testCbfsBadType(self):
2750 """Test an image header with a no specified location is detected"""
2751 with self.assertRaises(ValueError) as e:
2752 self._DoReadFile('126_cbfs_bad_type.dts')
2753 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2754
Simon Glass6b156f82019-07-08 14:25:43 -06002755 def testList(self):
2756 """Test listing the files in an image"""
2757 self._CheckLz4()
2758 data = self._DoReadFile('127_list.dts')
2759 image = control.images['image']
2760 entries = image.BuildEntryList()
2761 self.assertEqual(7, len(entries))
2762
2763 ent = entries[0]
2764 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002765 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002766 self.assertEqual('section', ent.etype)
2767 self.assertEqual(len(data), ent.size)
2768 self.assertEqual(0, ent.image_pos)
2769 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002770 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002771
2772 ent = entries[1]
2773 self.assertEqual(1, ent.indent)
2774 self.assertEqual('u-boot', ent.name)
2775 self.assertEqual('u-boot', ent.etype)
2776 self.assertEqual(len(U_BOOT_DATA), ent.size)
2777 self.assertEqual(0, ent.image_pos)
2778 self.assertEqual(None, ent.uncomp_size)
2779 self.assertEqual(0, ent.offset)
2780
2781 ent = entries[2]
2782 self.assertEqual(1, ent.indent)
2783 self.assertEqual('section', ent.name)
2784 self.assertEqual('section', ent.etype)
2785 section_size = ent.size
2786 self.assertEqual(0x100, ent.image_pos)
2787 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002788 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002789
2790 ent = entries[3]
2791 self.assertEqual(2, ent.indent)
2792 self.assertEqual('cbfs', ent.name)
2793 self.assertEqual('cbfs', ent.etype)
2794 self.assertEqual(0x400, ent.size)
2795 self.assertEqual(0x100, ent.image_pos)
2796 self.assertEqual(None, ent.uncomp_size)
2797 self.assertEqual(0, ent.offset)
2798
2799 ent = entries[4]
2800 self.assertEqual(3, ent.indent)
2801 self.assertEqual('u-boot', ent.name)
2802 self.assertEqual('u-boot', ent.etype)
2803 self.assertEqual(len(U_BOOT_DATA), ent.size)
2804 self.assertEqual(0x138, ent.image_pos)
2805 self.assertEqual(None, ent.uncomp_size)
2806 self.assertEqual(0x38, ent.offset)
2807
2808 ent = entries[5]
2809 self.assertEqual(3, ent.indent)
2810 self.assertEqual('u-boot-dtb', ent.name)
2811 self.assertEqual('text', ent.etype)
2812 self.assertGreater(len(COMPRESS_DATA), ent.size)
2813 self.assertEqual(0x178, ent.image_pos)
2814 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2815 self.assertEqual(0x78, ent.offset)
2816
2817 ent = entries[6]
2818 self.assertEqual(2, ent.indent)
2819 self.assertEqual('u-boot-dtb', ent.name)
2820 self.assertEqual('u-boot-dtb', ent.etype)
2821 self.assertEqual(0x500, ent.image_pos)
2822 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2823 dtb_size = ent.size
2824 # Compressing this data expands it since headers are added
2825 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2826 self.assertEqual(0x400, ent.offset)
2827
2828 self.assertEqual(len(data), 0x100 + section_size)
2829 self.assertEqual(section_size, 0x400 + dtb_size)
2830
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002831 def testFindFdtmap(self):
2832 """Test locating an FDT map in an image"""
2833 self._CheckLz4()
2834 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2835 image = control.images['image']
2836 entries = image.GetEntries()
2837 entry = entries['fdtmap']
2838 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2839
2840 def testFindFdtmapMissing(self):
2841 """Test failing to locate an FDP map"""
2842 data = self._DoReadFile('005_simple.dts')
2843 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2844
Simon Glassed39a3c2019-07-08 14:25:45 -06002845 def testFindImageHeader(self):
2846 """Test locating a image header"""
2847 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002848 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002849 image = control.images['image']
2850 entries = image.GetEntries()
2851 entry = entries['fdtmap']
2852 # The header should point to the FDT map
2853 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2854
2855 def testFindImageHeaderStart(self):
2856 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002857 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002858 image = control.images['image']
2859 entries = image.GetEntries()
2860 entry = entries['fdtmap']
2861 # The header should point to the FDT map
2862 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2863
2864 def testFindImageHeaderMissing(self):
2865 """Test failing to locate an image header"""
2866 data = self._DoReadFile('005_simple.dts')
2867 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2868
Simon Glassb8424fa2019-07-08 14:25:46 -06002869 def testReadImage(self):
2870 """Test reading an image and accessing its FDT map"""
2871 self._CheckLz4()
2872 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002873 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002874 orig_image = control.images['image']
2875 image = Image.FromFile(image_fname)
2876 self.assertEqual(orig_image.GetEntries().keys(),
2877 image.GetEntries().keys())
2878
2879 orig_entry = orig_image.GetEntries()['fdtmap']
2880 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002881 self.assertEqual(orig_entry.offset, entry.offset)
2882 self.assertEqual(orig_entry.size, entry.size)
2883 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002884
2885 def testReadImageNoHeader(self):
2886 """Test accessing an image's FDT map without an image header"""
2887 self._CheckLz4()
2888 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002889 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002890 image = Image.FromFile(image_fname)
2891 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002892 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002893
2894 def testReadImageFail(self):
2895 """Test failing to read an image image's FDT map"""
2896 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002897 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002898 with self.assertRaises(ValueError) as e:
2899 image = Image.FromFile(image_fname)
2900 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002901
Simon Glassb2fd11d2019-07-08 14:25:48 -06002902 def testListCmd(self):
2903 """Test listing the files in an image using an Fdtmap"""
2904 self._CheckLz4()
2905 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2906
2907 # lz4 compression size differs depending on the version
2908 image = control.images['image']
2909 entries = image.GetEntries()
2910 section_size = entries['section'].size
2911 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2912 fdtmap_offset = entries['fdtmap'].offset
2913
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002914 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002915 try:
2916 tmpdir, updated_fname = self._SetupImageInTmpdir()
2917 with test_util.capture_sys_output() as (stdout, stderr):
2918 self._DoBinman('ls', '-i', updated_fname)
2919 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002920 if tmpdir:
2921 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002922 lines = stdout.getvalue().splitlines()
2923 expected = [
2924'Name Image-pos Size Entry-type Offset Uncomp-size',
2925'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002926'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002927' u-boot 0 4 u-boot 0',
2928' section 100 %x section 100' % section_size,
2929' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002930' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002931' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002932' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002933' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002934 (fdtmap_offset, fdtmap_offset),
2935' image-header bf8 8 image-header bf8',
2936 ]
2937 self.assertEqual(expected, lines)
2938
2939 def testListCmdFail(self):
2940 """Test failing to list an image"""
2941 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002942 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002943 try:
2944 tmpdir, updated_fname = self._SetupImageInTmpdir()
2945 with self.assertRaises(ValueError) as e:
2946 self._DoBinman('ls', '-i', updated_fname)
2947 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002948 if tmpdir:
2949 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002950 self.assertIn("Cannot find FDT map in image", str(e.exception))
2951
2952 def _RunListCmd(self, paths, expected):
2953 """List out entries and check the result
2954
2955 Args:
2956 paths: List of paths to pass to the list command
2957 expected: Expected list of filenames to be returned, in order
2958 """
2959 self._CheckLz4()
2960 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002961 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002962 image = Image.FromFile(image_fname)
2963 lines = image.GetListEntries(paths)[1]
2964 files = [line[0].strip() for line in lines[1:]]
2965 self.assertEqual(expected, files)
2966
2967 def testListCmdSection(self):
2968 """Test listing the files in a section"""
2969 self._RunListCmd(['section'],
2970 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2971
2972 def testListCmdFile(self):
2973 """Test listing a particular file"""
2974 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2975
2976 def testListCmdWildcard(self):
2977 """Test listing a wildcarded file"""
2978 self._RunListCmd(['*boot*'],
2979 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2980
2981 def testListCmdWildcardMulti(self):
2982 """Test listing a wildcarded file"""
2983 self._RunListCmd(['*cb*', '*head*'],
2984 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2985
2986 def testListCmdEmpty(self):
2987 """Test listing a wildcarded file"""
2988 self._RunListCmd(['nothing'], [])
2989
2990 def testListCmdPath(self):
2991 """Test listing the files in a sub-entry of a section"""
2992 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2993
Simon Glass4c613bf2019-07-08 14:25:50 -06002994 def _RunExtractCmd(self, entry_name, decomp=True):
2995 """Extract an entry from an image
2996
2997 Args:
2998 entry_name: Entry name to extract
2999 decomp: True to decompress the data if compressed, False to leave
3000 it in its raw uncompressed format
3001
3002 Returns:
3003 data from entry
3004 """
3005 self._CheckLz4()
3006 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003007 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06003008 return control.ReadEntry(image_fname, entry_name, decomp)
3009
3010 def testExtractSimple(self):
3011 """Test extracting a single file"""
3012 data = self._RunExtractCmd('u-boot')
3013 self.assertEqual(U_BOOT_DATA, data)
3014
Simon Glass980a2842019-07-08 14:25:52 -06003015 def testExtractSection(self):
3016 """Test extracting the files in a section"""
3017 data = self._RunExtractCmd('section')
3018 cbfs_data = data[:0x400]
3019 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003020 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003021 dtb_data = data[0x400:]
3022 dtb = self._decompress(dtb_data)
3023 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3024
3025 def testExtractCompressed(self):
3026 """Test extracting compressed data"""
3027 data = self._RunExtractCmd('section/u-boot-dtb')
3028 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3029
3030 def testExtractRaw(self):
3031 """Test extracting compressed data without decompressing it"""
3032 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3033 dtb = self._decompress(data)
3034 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3035
3036 def testExtractCbfs(self):
3037 """Test extracting CBFS data"""
3038 data = self._RunExtractCmd('section/cbfs/u-boot')
3039 self.assertEqual(U_BOOT_DATA, data)
3040
3041 def testExtractCbfsCompressed(self):
3042 """Test extracting CBFS compressed data"""
3043 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3044 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3045
3046 def testExtractCbfsRaw(self):
3047 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003048 bintool = self.comp_bintools['lzma_alone']
3049 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003050 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003051 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003052 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3053
Simon Glass4c613bf2019-07-08 14:25:50 -06003054 def testExtractBadEntry(self):
3055 """Test extracting a bad section path"""
3056 with self.assertRaises(ValueError) as e:
3057 self._RunExtractCmd('section/does-not-exist')
3058 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3059 str(e.exception))
3060
3061 def testExtractMissingFile(self):
3062 """Test extracting file that does not exist"""
3063 with self.assertRaises(IOError) as e:
3064 control.ReadEntry('missing-file', 'name')
3065
3066 def testExtractBadFile(self):
3067 """Test extracting an invalid file"""
3068 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003069 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003070 with self.assertRaises(ValueError) as e:
3071 control.ReadEntry(fname, 'name')
3072
Simon Glass980a2842019-07-08 14:25:52 -06003073 def testExtractCmd(self):
3074 """Test extracting a file fron an image on the command line"""
3075 self._CheckLz4()
3076 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003077 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003078 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003079 try:
3080 tmpdir, updated_fname = self._SetupImageInTmpdir()
3081 with test_util.capture_sys_output() as (stdout, stderr):
3082 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3083 '-f', fname)
3084 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003085 if tmpdir:
3086 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003087 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003088 self.assertEqual(U_BOOT_DATA, data)
3089
3090 def testExtractOneEntry(self):
3091 """Test extracting a single entry fron an image """
3092 self._CheckLz4()
3093 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003094 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003095 fname = os.path.join(self._indir, 'output.extact')
3096 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003097 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003098 self.assertEqual(U_BOOT_DATA, data)
3099
3100 def _CheckExtractOutput(self, decomp):
3101 """Helper to test file output with and without decompression
3102
3103 Args:
3104 decomp: True to decompress entry data, False to output it raw
3105 """
3106 def _CheckPresent(entry_path, expect_data, expect_size=None):
3107 """Check and remove expected file
3108
3109 This checks the data/size of a file and removes the file both from
3110 the outfiles set and from the output directory. Once all files are
3111 processed, both the set and directory should be empty.
3112
3113 Args:
3114 entry_path: Entry path
3115 expect_data: Data to expect in file, or None to skip check
3116 expect_size: Size of data to expect in file, or None to skip
3117 """
3118 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003119 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003120 os.remove(path)
3121 if expect_data:
3122 self.assertEqual(expect_data, data)
3123 elif expect_size:
3124 self.assertEqual(expect_size, len(data))
3125 outfiles.remove(path)
3126
3127 def _CheckDirPresent(name):
3128 """Remove expected directory
3129
3130 This gives an error if the directory does not exist as expected
3131
3132 Args:
3133 name: Name of directory to remove
3134 """
3135 path = os.path.join(outdir, name)
3136 os.rmdir(path)
3137
3138 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003139 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003140 outdir = os.path.join(self._indir, 'extract')
3141 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3142
3143 # Create a set of all file that were output (should be 9)
3144 outfiles = set()
3145 for root, dirs, files in os.walk(outdir):
3146 outfiles |= set([os.path.join(root, fname) for fname in files])
3147 self.assertEqual(9, len(outfiles))
3148 self.assertEqual(9, len(einfos))
3149
3150 image = control.images['image']
3151 entries = image.GetEntries()
3152
3153 # Check the 9 files in various ways
3154 section = entries['section']
3155 section_entries = section.GetEntries()
3156 cbfs_entries = section_entries['cbfs'].GetEntries()
3157 _CheckPresent('u-boot', U_BOOT_DATA)
3158 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3159 dtb_len = EXTRACT_DTB_SIZE
3160 if not decomp:
3161 dtb_len = cbfs_entries['u-boot-dtb'].size
3162 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3163 if not decomp:
3164 dtb_len = section_entries['u-boot-dtb'].size
3165 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3166
3167 fdtmap = entries['fdtmap']
3168 _CheckPresent('fdtmap', fdtmap.data)
3169 hdr = entries['image-header']
3170 _CheckPresent('image-header', hdr.data)
3171
3172 _CheckPresent('section/root', section.data)
3173 cbfs = section_entries['cbfs']
3174 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003175 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003176 _CheckPresent('root', data)
3177
3178 # There should be no files left. Remove all the directories to check.
3179 # If there are any files/dirs remaining, one of these checks will fail.
3180 self.assertEqual(0, len(outfiles))
3181 _CheckDirPresent('section/cbfs')
3182 _CheckDirPresent('section')
3183 _CheckDirPresent('')
3184 self.assertFalse(os.path.exists(outdir))
3185
3186 def testExtractAllEntries(self):
3187 """Test extracting all entries"""
3188 self._CheckLz4()
3189 self._CheckExtractOutput(decomp=True)
3190
3191 def testExtractAllEntriesRaw(self):
3192 """Test extracting all entries without decompressing them"""
3193 self._CheckLz4()
3194 self._CheckExtractOutput(decomp=False)
3195
3196 def testExtractSelectedEntries(self):
3197 """Test extracting some entries"""
3198 self._CheckLz4()
3199 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003200 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003201 outdir = os.path.join(self._indir, 'extract')
3202 einfos = control.ExtractEntries(image_fname, None, outdir,
3203 ['*cb*', '*head*'])
3204
3205 # File output is tested by testExtractAllEntries(), so just check that
3206 # the expected entries are selected
3207 names = [einfo.name for einfo in einfos]
3208 self.assertEqual(names,
3209 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3210
3211 def testExtractNoEntryPaths(self):
3212 """Test extracting some entries"""
3213 self._CheckLz4()
3214 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003215 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003216 with self.assertRaises(ValueError) as e:
3217 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003218 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003219 str(e.exception))
3220
3221 def testExtractTooManyEntryPaths(self):
3222 """Test extracting some entries"""
3223 self._CheckLz4()
3224 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003225 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003226 with self.assertRaises(ValueError) as e:
3227 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003228 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003229 str(e.exception))
3230
Simon Glass52d06212019-07-08 14:25:53 -06003231 def testPackAlignSection(self):
3232 """Test that sections can have alignment"""
3233 self._DoReadFile('131_pack_align_section.dts')
3234
3235 self.assertIn('image', control.images)
3236 image = control.images['image']
3237 entries = image.GetEntries()
3238 self.assertEqual(3, len(entries))
3239
3240 # First u-boot
3241 self.assertIn('u-boot', entries)
3242 entry = entries['u-boot']
3243 self.assertEqual(0, entry.offset)
3244 self.assertEqual(0, entry.image_pos)
3245 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3246 self.assertEqual(len(U_BOOT_DATA), entry.size)
3247
3248 # Section0
3249 self.assertIn('section0', entries)
3250 section0 = entries['section0']
3251 self.assertEqual(0x10, section0.offset)
3252 self.assertEqual(0x10, section0.image_pos)
3253 self.assertEqual(len(U_BOOT_DATA), section0.size)
3254
3255 # Second u-boot
3256 section_entries = section0.GetEntries()
3257 self.assertIn('u-boot', section_entries)
3258 entry = section_entries['u-boot']
3259 self.assertEqual(0, entry.offset)
3260 self.assertEqual(0x10, entry.image_pos)
3261 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3262 self.assertEqual(len(U_BOOT_DATA), entry.size)
3263
3264 # Section1
3265 self.assertIn('section1', entries)
3266 section1 = entries['section1']
3267 self.assertEqual(0x14, section1.offset)
3268 self.assertEqual(0x14, section1.image_pos)
3269 self.assertEqual(0x20, section1.size)
3270
3271 # Second u-boot
3272 section_entries = section1.GetEntries()
3273 self.assertIn('u-boot', section_entries)
3274 entry = section_entries['u-boot']
3275 self.assertEqual(0, entry.offset)
3276 self.assertEqual(0x14, entry.image_pos)
3277 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3278 self.assertEqual(len(U_BOOT_DATA), entry.size)
3279
3280 # Section2
3281 self.assertIn('section2', section_entries)
3282 section2 = section_entries['section2']
3283 self.assertEqual(0x4, section2.offset)
3284 self.assertEqual(0x18, section2.image_pos)
3285 self.assertEqual(4, section2.size)
3286
3287 # Third u-boot
3288 section_entries = section2.GetEntries()
3289 self.assertIn('u-boot', section_entries)
3290 entry = section_entries['u-boot']
3291 self.assertEqual(0, entry.offset)
3292 self.assertEqual(0x18, entry.image_pos)
3293 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3294 self.assertEqual(len(U_BOOT_DATA), entry.size)
3295
Simon Glassf8a54bc2019-07-20 12:23:56 -06003296 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3297 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003298 """Replace an entry in an image
3299
3300 This writes the entry data to update it, then opens the updated file and
3301 returns the value that it now finds there.
3302
3303 Args:
3304 entry_name: Entry name to replace
3305 data: Data to replace it with
3306 decomp: True to compress the data if needed, False if data is
3307 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003308 allow_resize: True to allow entries to change size, False to raise
3309 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003310
3311 Returns:
3312 Tuple:
3313 data from entry
3314 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003315 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003316 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003317 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003318 update_dtb=True)[1]
3319
3320 self.assertIn('image', control.images)
3321 image = control.images['image']
3322 entries = image.GetEntries()
3323 orig_dtb_data = entries['u-boot-dtb'].data
3324 orig_fdtmap_data = entries['fdtmap'].data
3325
Simon Glass80025522022-01-29 14:14:04 -07003326 image_fname = tools.get_output_filename('image.bin')
3327 updated_fname = tools.get_output_filename('image-updated.bin')
3328 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003329 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3330 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003331 data = control.ReadEntry(updated_fname, entry_name, decomp)
3332
Simon Glassf8a54bc2019-07-20 12:23:56 -06003333 # The DT data should not change unless resized:
3334 if not allow_resize:
3335 new_dtb_data = entries['u-boot-dtb'].data
3336 self.assertEqual(new_dtb_data, orig_dtb_data)
3337 new_fdtmap_data = entries['fdtmap'].data
3338 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003339
Simon Glassf8a54bc2019-07-20 12:23:56 -06003340 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003341
3342 def testReplaceSimple(self):
3343 """Test replacing a single file"""
3344 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003345 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3346 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003347 self.assertEqual(expected, data)
3348
3349 # Test that the state looks right. There should be an FDT for the fdtmap
3350 # that we jsut read back in, and it should match what we find in the
3351 # 'control' tables. Checking for an FDT that does not exist should
3352 # return None.
3353 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003354 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003355 self.assertEqual(expected_fdtmap, fdtmap)
3356
3357 dtb = state.GetFdtForEtype('fdtmap')
3358 self.assertEqual(dtb.GetContents(), fdtmap)
3359
3360 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3361 self.assertIsNone(missing_path)
3362 self.assertIsNone(missing_fdtmap)
3363
3364 missing_dtb = state.GetFdtForEtype('missing')
3365 self.assertIsNone(missing_dtb)
3366
3367 self.assertEqual('/binman', state.fdt_path_prefix)
3368
3369 def testReplaceResizeFail(self):
3370 """Test replacing a file by something larger"""
3371 expected = U_BOOT_DATA + b'x'
3372 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003373 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3374 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003375 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3376 str(e.exception))
3377
3378 def testReplaceMulti(self):
3379 """Test replacing entry data where multiple images are generated"""
3380 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3381 update_dtb=True)[0]
3382 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003383 updated_fname = tools.get_output_filename('image-updated.bin')
3384 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003385 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003386 control.WriteEntry(updated_fname, entry_name, expected,
3387 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003388 data = control.ReadEntry(updated_fname, entry_name)
3389 self.assertEqual(expected, data)
3390
3391 # Check the state looks right.
3392 self.assertEqual('/binman/image', state.fdt_path_prefix)
3393
3394 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003395 image_fname = tools.get_output_filename('first-image.bin')
3396 updated_fname = tools.get_output_filename('first-updated.bin')
3397 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003398 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003399 control.WriteEntry(updated_fname, entry_name, expected,
3400 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003401 data = control.ReadEntry(updated_fname, entry_name)
3402 self.assertEqual(expected, data)
3403
3404 # Check the state looks right.
3405 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003406
Simon Glassfb30e292019-07-20 12:23:51 -06003407 def testUpdateFdtAllRepack(self):
3408 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003409 self._SetupSplElf()
3410 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003411 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3412 SECTION_SIZE = 0x300
3413 DTB_SIZE = 602
3414 FDTMAP_SIZE = 608
3415 base_expected = {
3416 'offset': 0,
3417 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3418 'image-pos': 0,
3419 'section:offset': 0,
3420 'section:size': SECTION_SIZE,
3421 'section:image-pos': 0,
3422 'section/u-boot-dtb:offset': 4,
3423 'section/u-boot-dtb:size': 636,
3424 'section/u-boot-dtb:image-pos': 4,
3425 'u-boot-spl-dtb:offset': SECTION_SIZE,
3426 'u-boot-spl-dtb:size': DTB_SIZE,
3427 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3428 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3429 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3430 'u-boot-tpl-dtb:size': DTB_SIZE,
3431 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3432 'fdtmap:size': FDTMAP_SIZE,
3433 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3434 }
3435 main_expected = {
3436 'section:orig-size': SECTION_SIZE,
3437 'section/u-boot-dtb:orig-offset': 4,
3438 }
3439
3440 # We expect three device-tree files in the output, with the first one
3441 # within a fixed-size section.
3442 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3443 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3444 # main U-Boot tree. All three should have the same positions and offset
3445 # except that the main tree should include the main_expected properties
3446 start = 4
3447 for item in ['', 'spl', 'tpl', None]:
3448 if item is None:
3449 start += 16 # Move past fdtmap header
3450 dtb = fdt.Fdt.FromData(data[start:])
3451 dtb.Scan()
3452 props = self._GetPropTree(dtb,
3453 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3454 prefix='/' if item is None else '/binman/')
3455 expected = dict(base_expected)
3456 if item:
3457 expected[item] = 0
3458 else:
3459 # Main DTB and fdtdec should include the 'orig-' properties
3460 expected.update(main_expected)
3461 # Helpful for debugging:
3462 #for prop in sorted(props):
3463 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3464 self.assertEqual(expected, props)
3465 if item == '':
3466 start = SECTION_SIZE
3467 else:
3468 start += dtb._fdt_obj.totalsize()
3469
Simon Glass11453762019-07-20 12:23:55 -06003470 def testFdtmapHeaderMiddle(self):
3471 """Test an FDT map in the middle of an image when it should be at end"""
3472 with self.assertRaises(ValueError) as e:
3473 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3474 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3475 str(e.exception))
3476
3477 def testFdtmapHeaderStartBad(self):
3478 """Test an FDT map in middle of an image when it should be at start"""
3479 with self.assertRaises(ValueError) as e:
3480 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3481 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3482 str(e.exception))
3483
3484 def testFdtmapHeaderEndBad(self):
3485 """Test an FDT map at the start of an image when it should be at end"""
3486 with self.assertRaises(ValueError) as e:
3487 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3488 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3489 str(e.exception))
3490
3491 def testFdtmapHeaderNoSize(self):
3492 """Test an image header at the end of an image with undefined size"""
3493 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3494
Simon Glassf8a54bc2019-07-20 12:23:56 -06003495 def testReplaceResize(self):
3496 """Test replacing a single file in an entry with a larger file"""
3497 expected = U_BOOT_DATA + b'x'
3498 data, _, image = self._RunReplaceCmd('u-boot', expected,
3499 dts='139_replace_repack.dts')
3500 self.assertEqual(expected, data)
3501
3502 entries = image.GetEntries()
3503 dtb_data = entries['u-boot-dtb'].data
3504 dtb = fdt.Fdt.FromData(dtb_data)
3505 dtb.Scan()
3506
3507 # The u-boot section should now be larger in the dtb
3508 node = dtb.GetNode('/binman/u-boot')
3509 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3510
3511 # Same for the fdtmap
3512 fdata = entries['fdtmap'].data
3513 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3514 fdtb.Scan()
3515 fnode = fdtb.GetNode('/u-boot')
3516 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3517
3518 def testReplaceResizeNoRepack(self):
3519 """Test replacing an entry with a larger file when not allowed"""
3520 expected = U_BOOT_DATA + b'x'
3521 with self.assertRaises(ValueError) as e:
3522 self._RunReplaceCmd('u-boot', expected)
3523 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3524 str(e.exception))
3525
Simon Glass9d8ee322019-07-20 12:23:58 -06003526 def testEntryShrink(self):
3527 """Test contracting an entry after it is packed"""
3528 try:
3529 state.SetAllowEntryContraction(True)
3530 data = self._DoReadFileDtb('140_entry_shrink.dts',
3531 update_dtb=True)[0]
3532 finally:
3533 state.SetAllowEntryContraction(False)
3534 self.assertEqual(b'a', data[:1])
3535 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3536 self.assertEqual(b'a', data[-1:])
3537
3538 def testEntryShrinkFail(self):
3539 """Test not being allowed to contract an entry after it is packed"""
3540 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3541
3542 # In this case there is a spare byte at the end of the data. The size of
3543 # the contents is only 1 byte but we still have the size before it
3544 # shrunk.
3545 self.assertEqual(b'a\0', data[:2])
3546 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3547 self.assertEqual(b'a\0', data[-2:])
3548
Simon Glass70e32982019-07-20 12:24:01 -06003549 def testDescriptorOffset(self):
3550 """Test that the Intel descriptor is always placed at at the start"""
3551 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3552 image = control.images['image']
3553 entries = image.GetEntries()
3554 desc = entries['intel-descriptor']
Simon Glassed836ac2025-02-26 09:26:17 -07003555 self.assertEqual(0xff800000, desc.offset)
3556 self.assertEqual(0xff800000, desc.image_pos)
Simon Glass70e32982019-07-20 12:24:01 -06003557
Simon Glass37fdd142019-07-20 12:24:06 -06003558 def testReplaceCbfs(self):
3559 """Test replacing a single file in CBFS without changing the size"""
3560 self._CheckLz4()
3561 expected = b'x' * len(U_BOOT_DATA)
3562 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003563 updated_fname = tools.get_output_filename('image-updated.bin')
3564 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003565 entry_name = 'section/cbfs/u-boot'
3566 control.WriteEntry(updated_fname, entry_name, expected,
3567 allow_resize=True)
3568 data = control.ReadEntry(updated_fname, entry_name)
3569 self.assertEqual(expected, data)
3570
3571 def testReplaceResizeCbfs(self):
3572 """Test replacing a single file in CBFS with one of a different size"""
3573 self._CheckLz4()
3574 expected = U_BOOT_DATA + b'x'
3575 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003576 updated_fname = tools.get_output_filename('image-updated.bin')
3577 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003578 entry_name = 'section/cbfs/u-boot'
3579 control.WriteEntry(updated_fname, entry_name, expected,
3580 allow_resize=True)
3581 data = control.ReadEntry(updated_fname, entry_name)
3582 self.assertEqual(expected, data)
3583
Simon Glass30033c22019-07-20 12:24:15 -06003584 def _SetupForReplace(self):
3585 """Set up some files to use to replace entries
3586
3587 This generates an image, copies it to a new file, extracts all the files
3588 in it and updates some of them
3589
3590 Returns:
3591 List
3592 Image filename
3593 Output directory
3594 Expected values for updated entries, each a string
3595 """
3596 data = self._DoReadFileRealDtb('143_replace_all.dts')
3597
Simon Glass80025522022-01-29 14:14:04 -07003598 updated_fname = tools.get_output_filename('image-updated.bin')
3599 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003600
3601 outdir = os.path.join(self._indir, 'extract')
3602 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3603
3604 expected1 = b'x' + U_BOOT_DATA + b'y'
3605 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003606 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003607
3608 expected2 = b'a' + U_BOOT_DATA + b'b'
3609 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003610 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003611
3612 expected_text = b'not the same text'
3613 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003614 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003615
3616 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3617 dtb = fdt.FdtScan(dtb_fname)
3618 node = dtb.GetNode('/binman/text')
3619 node.AddString('my-property', 'the value')
3620 dtb.Sync(auto_resize=True)
3621 dtb.Flush()
3622
3623 return updated_fname, outdir, expected1, expected2, expected_text
3624
3625 def _CheckReplaceMultiple(self, entry_paths):
3626 """Handle replacing the contents of multiple entries
3627
3628 Args:
3629 entry_paths: List of entry paths to replace
3630
3631 Returns:
3632 List
3633 Dict of entries in the image:
3634 key: Entry name
3635 Value: Entry object
3636 Expected values for updated entries, each a string
3637 """
3638 updated_fname, outdir, expected1, expected2, expected_text = (
3639 self._SetupForReplace())
3640 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3641
3642 image = Image.FromFile(updated_fname)
3643 image.LoadData()
3644 return image.GetEntries(), expected1, expected2, expected_text
3645
3646 def testReplaceAll(self):
3647 """Test replacing the contents of all entries"""
3648 entries, expected1, expected2, expected_text = (
3649 self._CheckReplaceMultiple([]))
3650 data = entries['u-boot'].data
3651 self.assertEqual(expected1, data)
3652
3653 data = entries['u-boot2'].data
3654 self.assertEqual(expected2, data)
3655
3656 data = entries['text'].data
3657 self.assertEqual(expected_text, data)
3658
3659 # Check that the device tree is updated
3660 data = entries['u-boot-dtb'].data
3661 dtb = fdt.Fdt.FromData(data)
3662 dtb.Scan()
3663 node = dtb.GetNode('/binman/text')
3664 self.assertEqual('the value', node.props['my-property'].value)
3665
3666 def testReplaceSome(self):
3667 """Test replacing the contents of a few entries"""
3668 entries, expected1, expected2, expected_text = (
3669 self._CheckReplaceMultiple(['u-boot2', 'text']))
3670
3671 # This one should not change
3672 data = entries['u-boot'].data
3673 self.assertEqual(U_BOOT_DATA, data)
3674
3675 data = entries['u-boot2'].data
3676 self.assertEqual(expected2, data)
3677
3678 data = entries['text'].data
3679 self.assertEqual(expected_text, data)
3680
3681 def testReplaceCmd(self):
3682 """Test replacing a file fron an image on the command line"""
3683 self._DoReadFileRealDtb('143_replace_all.dts')
3684
3685 try:
3686 tmpdir, updated_fname = self._SetupImageInTmpdir()
3687
3688 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3689 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003690 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003691
3692 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003693 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003694 self.assertEqual(expected, data[:len(expected)])
3695 map_fname = os.path.join(tmpdir, 'image-updated.map')
3696 self.assertFalse(os.path.exists(map_fname))
3697 finally:
3698 shutil.rmtree(tmpdir)
3699
3700 def testReplaceCmdSome(self):
3701 """Test replacing some files fron an image on the command line"""
3702 updated_fname, outdir, expected1, expected2, expected_text = (
3703 self._SetupForReplace())
3704
3705 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3706 'u-boot2', 'text')
3707
Simon Glass80025522022-01-29 14:14:04 -07003708 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003709 image = Image.FromFile(updated_fname)
3710 image.LoadData()
3711 entries = image.GetEntries()
3712
3713 # This one should not change
3714 data = entries['u-boot'].data
3715 self.assertEqual(U_BOOT_DATA, data)
3716
3717 data = entries['u-boot2'].data
3718 self.assertEqual(expected2, data)
3719
3720 data = entries['text'].data
3721 self.assertEqual(expected_text, data)
3722
3723 def testReplaceMissing(self):
3724 """Test replacing entries where the file is missing"""
3725 updated_fname, outdir, expected1, expected2, expected_text = (
3726 self._SetupForReplace())
3727
3728 # Remove one of the files, to generate a warning
3729 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3730 os.remove(u_boot_fname1)
3731
3732 with test_util.capture_sys_output() as (stdout, stderr):
3733 control.ReplaceEntries(updated_fname, None, outdir, [])
3734 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003735 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003736
3737 def testReplaceCmdMap(self):
3738 """Test replacing a file fron an image on the command line"""
3739 self._DoReadFileRealDtb('143_replace_all.dts')
3740
3741 try:
3742 tmpdir, updated_fname = self._SetupImageInTmpdir()
3743
3744 fname = os.path.join(self._indir, 'update-u-boot.bin')
3745 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003746 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003747
3748 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3749 '-f', fname, '-m')
3750 map_fname = os.path.join(tmpdir, 'image-updated.map')
3751 self.assertTrue(os.path.exists(map_fname))
3752 finally:
3753 shutil.rmtree(tmpdir)
3754
3755 def testReplaceNoEntryPaths(self):
3756 """Test replacing an entry without an entry path"""
3757 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003758 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003759 with self.assertRaises(ValueError) as e:
3760 control.ReplaceEntries(image_fname, 'fname', None, [])
3761 self.assertIn('Must specify an entry path to read with -f',
3762 str(e.exception))
3763
3764 def testReplaceTooManyEntryPaths(self):
3765 """Test extracting some entries"""
3766 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003767 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003768 with self.assertRaises(ValueError) as e:
3769 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3770 self.assertIn('Must specify exactly one entry path to write with -f',
3771 str(e.exception))
3772
Simon Glass0b074d62019-08-24 07:22:48 -06003773 def testPackReset16(self):
3774 """Test that an image with an x86 reset16 region can be created"""
3775 data = self._DoReadFile('144_x86_reset16.dts')
3776 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3777
3778 def testPackReset16Spl(self):
3779 """Test that an image with an x86 reset16-spl region can be created"""
3780 data = self._DoReadFile('145_x86_reset16_spl.dts')
3781 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3782
3783 def testPackReset16Tpl(self):
3784 """Test that an image with an x86 reset16-tpl region can be created"""
3785 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3786 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3787
Simon Glass232f90c2019-08-24 07:22:50 -06003788 def testPackIntelFit(self):
3789 """Test that an image with an Intel FIT and pointer can be created"""
3790 data = self._DoReadFile('147_intel_fit.dts')
3791 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3792 fit = data[16:32];
3793 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3794 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3795
3796 image = control.images['image']
3797 entries = image.GetEntries()
Simon Glassed836ac2025-02-26 09:26:17 -07003798 expected_ptr = entries['intel-fit'].image_pos #- (1 << 32)
3799 self.assertEqual(expected_ptr, ptr + (1 << 32))
Simon Glass232f90c2019-08-24 07:22:50 -06003800
3801 def testPackIntelFitMissing(self):
3802 """Test detection of a FIT pointer with not FIT region"""
3803 with self.assertRaises(ValueError) as e:
3804 self._DoReadFile('148_intel_fit_missing.dts')
3805 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3806 str(e.exception))
3807
Simon Glass72555fa2019-11-06 17:22:44 -07003808 def _CheckSymbolsTplSection(self, dts, expected_vals):
3809 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003810 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003811 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003812 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003813 self.assertEqual(expected1, data[:upto1])
3814
3815 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003816 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003817 self.assertEqual(expected2, data[upto1:upto2])
3818
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003819 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003820 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003821 self.assertEqual(expected3, data[upto2:upto3])
3822
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003823 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003824 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3825
3826 def testSymbolsTplSection(self):
3827 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3828 self._SetupSplElf('u_boot_binman_syms')
3829 self._SetupTplElf('u_boot_binman_syms')
3830 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003831 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003832
3833 def testSymbolsTplSectionX86(self):
3834 """Test binman can assign symbols in a section with end-at-4gb"""
3835 self._SetupSplElf('u_boot_binman_syms_x86')
3836 self._SetupTplElf('u_boot_binman_syms_x86')
3837 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003838 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003839 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003840
Simon Glass98c59572019-08-24 07:23:03 -06003841 def testPackX86RomIfwiSectiom(self):
3842 """Test that a section can be placed in an IFWI region"""
3843 self._SetupIfwi('fitimage.bin')
3844 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3845 self._CheckIfwi(data)
3846
Simon Glassba7985d2019-08-24 07:23:07 -06003847 def testPackFspM(self):
3848 """Test that an image with a FSP memory-init binary can be created"""
3849 data = self._DoReadFile('152_intel_fsp_m.dts')
3850 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3851
Simon Glass4d9086d2019-10-20 21:31:35 -06003852 def testPackFspS(self):
3853 """Test that an image with a FSP silicon-init binary can be created"""
3854 data = self._DoReadFile('153_intel_fsp_s.dts')
3855 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003856
Simon Glass9ea87b22019-10-20 21:31:36 -06003857 def testPackFspT(self):
3858 """Test that an image with a FSP temp-ram-init binary can be created"""
3859 data = self._DoReadFile('154_intel_fsp_t.dts')
3860 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3861
Simon Glass48f3aad2020-07-09 18:39:31 -06003862 def testMkimage(self):
3863 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003864 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003865 data = self._DoReadFile('156_mkimage.dts')
3866
3867 # Just check that the data appears in the file somewhere
3868 self.assertIn(U_BOOT_SPL_DATA, data)
3869
Simon Glass66152ce2022-01-09 20:14:09 -07003870 def testMkimageMissing(self):
3871 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003872 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003873 with test_util.capture_sys_output() as (_, stderr):
3874 self._DoTestFile('156_mkimage.dts',
3875 force_missing_bintools='mkimage')
3876 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003877 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003878
Simon Glass5e560182020-07-09 18:39:36 -06003879 def testExtblob(self):
3880 """Test an image with an external blob"""
3881 data = self._DoReadFile('157_blob_ext.dts')
3882 self.assertEqual(REFCODE_DATA, data)
3883
3884 def testExtblobMissing(self):
3885 """Test an image with a missing external blob"""
3886 with self.assertRaises(ValueError) as e:
3887 self._DoReadFile('158_blob_ext_missing.dts')
3888 self.assertIn("Filename 'missing-file' not found in input path",
3889 str(e.exception))
3890
Simon Glass5d94cc62020-07-09 18:39:38 -06003891 def testExtblobMissingOk(self):
3892 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003893 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003894 ret = self._DoTestFile('158_blob_ext_missing.dts',
3895 allow_missing=True)
3896 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003897 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003898 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003899 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003900 self.assertIn('Some images are invalid', err)
3901
3902 def testExtblobMissingOkFlag(self):
3903 """Test an image with an missing external blob allowed with -W"""
3904 with test_util.capture_sys_output() as (stdout, stderr):
3905 ret = self._DoTestFile('158_blob_ext_missing.dts',
3906 allow_missing=True, ignore_missing=True)
3907 self.assertEqual(0, ret)
3908 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003909 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003910 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003911 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003912
3913 def testExtblobMissingOkSect(self):
3914 """Test an image with an missing external blob that is allowed"""
3915 with test_util.capture_sys_output() as (stdout, stderr):
3916 self._DoTestFile('159_blob_ext_missing_sect.dts',
3917 allow_missing=True)
3918 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003919 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003920
Simon Glasse88cef92020-07-09 18:39:41 -06003921 def testPackX86RomMeMissingDesc(self):
3922 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003923 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003924 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003925 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003926 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003927
3928 def testPackX86RomMissingIfwi(self):
3929 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3930 self._SetupIfwi('fitimage.bin')
3931 pathname = os.path.join(self._indir, 'fitimage.bin')
3932 os.remove(pathname)
3933 with test_util.capture_sys_output() as (stdout, stderr):
3934 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3935 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003936 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003937
Simon Glass2a0fa982022-02-11 13:23:21 -07003938 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003939 """Test that zero-size overlapping regions are ignored"""
3940 self._DoTestFile('160_pack_overlap_zero.dts')
3941
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003942 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003943 # The data should be inside the FIT
3944 dtb = fdt.Fdt.FromData(fit_data)
3945 dtb.Scan()
3946 fnode = dtb.GetNode('/images/kernel')
3947 self.assertIn('data', fnode.props)
3948
3949 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003950 tools.write_file(fname, fit_data)
3951 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003952
3953 # Check a few features to make sure the plumbing works. We don't need
3954 # to test the operation of mkimage or dumpimage here. First convert the
3955 # output into a dict where the keys are the fields printed by dumpimage
3956 # and the values are a list of values for each field
3957 lines = out.splitlines()
3958
3959 # Converts "Compression: gzip compressed" into two groups:
3960 # 'Compression' and 'gzip compressed'
3961 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3962 vals = collections.defaultdict(list)
3963 for line in lines:
3964 mat = re_line.match(line)
3965 vals[mat.group(1)].append(mat.group(2))
3966
Brandon Maiera657bc62024-06-04 16:16:05 +00003967 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003968 self.assertIn('Created:', lines[1])
3969 self.assertIn('Image 0 (kernel)', vals)
3970 self.assertIn('Hash value', vals)
3971 data_sizes = vals.get('Data Size')
3972 self.assertIsNotNone(data_sizes)
3973 self.assertEqual(2, len(data_sizes))
3974 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003975 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3976 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3977
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003978 # Check if entry listing correctly omits /images/
3979 image = control.images['image']
3980 fit_entry = image.GetEntries()['fit']
3981 subentries = list(fit_entry.GetEntries().keys())
3982 expected = ['kernel', 'fdt-1']
3983 self.assertEqual(expected, subentries)
3984
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003985 def testSimpleFit(self):
3986 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003987 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003988 data = self._DoReadFile('161_fit.dts')
3989 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3990 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3991 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3992
3993 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3994
3995 def testSimpleFitExpandsSubentries(self):
3996 """Test that FIT images expand their subentries"""
3997 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3998 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3999 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4000 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
4001
4002 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06004003
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004004 def testSimpleFitImagePos(self):
4005 """Test that we have correct image-pos for FIT subentries"""
4006 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
4007 update_dtb=True)
4008 dtb = fdt.Fdt(out_dtb_fname)
4009 dtb.Scan()
4010 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4011
Simon Glassb7bad182022-03-05 20:19:01 -07004012 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004013 self.assertEqual({
4014 'image-pos': 0,
4015 'offset': 0,
4016 'size': 1890,
4017
4018 'u-boot:image-pos': 0,
4019 'u-boot:offset': 0,
4020 'u-boot:size': 4,
4021
4022 'fit:image-pos': 4,
4023 'fit:offset': 4,
4024 'fit:size': 1840,
4025
Simon Glassb7bad182022-03-05 20:19:01 -07004026 'fit/images/kernel:image-pos': 304,
4027 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004028 'fit/images/kernel:size': 4,
4029
Simon Glassb7bad182022-03-05 20:19:01 -07004030 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004031 'fit/images/kernel/u-boot:offset': 0,
4032 'fit/images/kernel/u-boot:size': 4,
4033
Simon Glassb7bad182022-03-05 20:19:01 -07004034 'fit/images/fdt-1:image-pos': 552,
4035 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004036 'fit/images/fdt-1:size': 6,
4037
Simon Glassb7bad182022-03-05 20:19:01 -07004038 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004039 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4040 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4041
4042 'u-boot-nodtb:image-pos': 1844,
4043 'u-boot-nodtb:offset': 1844,
4044 'u-boot-nodtb:size': 46,
4045 }, props)
4046
4047 # Actually check the data is where we think it is
4048 for node, expected in [
4049 ("u-boot", U_BOOT_DATA),
4050 ("fit/images/kernel", U_BOOT_DATA),
4051 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4052 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4053 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4054 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4055 ]:
4056 image_pos = props[f"{node}:image-pos"]
4057 size = props[f"{node}:size"]
4058 self.assertEqual(len(expected), size)
4059 self.assertEqual(expected, data[image_pos:image_pos+size])
4060
Simon Glass45d556d2020-07-09 18:39:45 -06004061 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004062 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004063 data = self._DoReadFile('162_fit_external.dts')
4064 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4065
Simon Glass7932c882022-01-09 20:13:39 -07004066 # Size of the external-data region as set up by mkimage
4067 external_data_size = len(U_BOOT_DATA) + 2
4068 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004069 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004070 len(U_BOOT_NODTB_DATA))
4071
Simon Glass45d556d2020-07-09 18:39:45 -06004072 # The data should be outside the FIT
4073 dtb = fdt.Fdt.FromData(fit_data)
4074 dtb.Scan()
4075 fnode = dtb.GetNode('/images/kernel')
4076 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004077 self.assertEqual(len(U_BOOT_DATA),
4078 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4079 fit_pos = 0x400;
4080 self.assertEqual(
4081 fit_pos,
4082 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4083
Brandon Maiera657bc62024-06-04 16:16:05 +00004084 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004085 actual_pos = len(U_BOOT_DATA) + fit_pos
4086 self.assertEqual(U_BOOT_DATA + b'aa',
4087 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004088
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004089 def testFitExternalImagePos(self):
4090 """Test that we have correct image-pos for external FIT subentries"""
4091 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4092 update_dtb=True)
4093 dtb = fdt.Fdt(out_dtb_fname)
4094 dtb.Scan()
4095 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4096
4097 self.assertEqual({
4098 'image-pos': 0,
4099 'offset': 0,
4100 'size': 1082,
4101
4102 'u-boot:image-pos': 0,
4103 'u-boot:offset': 0,
4104 'u-boot:size': 4,
4105
4106 'fit:size': 1032,
4107 'fit:offset': 4,
4108 'fit:image-pos': 4,
4109
4110 'fit/images/kernel:size': 4,
4111 'fit/images/kernel:offset': 1024,
4112 'fit/images/kernel:image-pos': 1028,
4113
4114 'fit/images/kernel/u-boot:size': 4,
4115 'fit/images/kernel/u-boot:offset': 0,
4116 'fit/images/kernel/u-boot:image-pos': 1028,
4117
4118 'fit/images/fdt-1:size': 2,
4119 'fit/images/fdt-1:offset': 1028,
4120 'fit/images/fdt-1:image-pos': 1032,
4121
4122 'fit/images/fdt-1/_testing:size': 2,
4123 'fit/images/fdt-1/_testing:offset': 0,
4124 'fit/images/fdt-1/_testing:image-pos': 1032,
4125
4126 'u-boot-nodtb:image-pos': 1036,
4127 'u-boot-nodtb:offset': 1036,
4128 'u-boot-nodtb:size': 46,
4129 }, props)
4130
4131 # Actually check the data is where we think it is
4132 for node, expected in [
4133 ("u-boot", U_BOOT_DATA),
4134 ("fit/images/kernel", U_BOOT_DATA),
4135 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4136 ("fit/images/fdt-1", b'aa'),
4137 ("fit/images/fdt-1/_testing", b'aa'),
4138 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4139 ]:
4140 image_pos = props[f"{node}:image-pos"]
4141 size = props[f"{node}:size"]
4142 self.assertEqual(len(expected), size)
4143 self.assertEqual(expected, data[image_pos:image_pos+size])
4144
Simon Glass66152ce2022-01-09 20:14:09 -07004145 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004146 """Test that binman complains if mkimage is missing"""
4147 with self.assertRaises(ValueError) as e:
4148 self._DoTestFile('162_fit_external.dts',
4149 force_missing_bintools='mkimage')
4150 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4151 str(e.exception))
4152
4153 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004154 """Test that binman still produces a FIT image if mkimage is missing"""
4155 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004156 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004157 force_missing_bintools='mkimage')
4158 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004159 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004160
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004161 def testSectionIgnoreHashSignature(self):
4162 """Test that sections ignore hash, signature nodes for its data"""
4163 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4164 expected = (U_BOOT_DATA + U_BOOT_DATA)
4165 self.assertEqual(expected, data)
4166
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004167 def testPadInSections(self):
4168 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004169 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4170 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004171 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4172 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004173 U_BOOT_DATA)
4174 self.assertEqual(expected, data)
4175
Simon Glassd12599d2020-10-26 17:40:09 -06004176 dtb = fdt.Fdt(out_dtb_fname)
4177 dtb.Scan()
4178 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4179 expected = {
4180 'image-pos': 0,
4181 'offset': 0,
4182 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4183
4184 'section:image-pos': 0,
4185 'section:offset': 0,
4186 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4187
4188 'section/before:image-pos': 0,
4189 'section/before:offset': 0,
4190 'section/before:size': len(U_BOOT_DATA),
4191
4192 'section/u-boot:image-pos': 4,
4193 'section/u-boot:offset': 4,
4194 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4195
4196 'section/after:image-pos': 26,
4197 'section/after:offset': 26,
4198 'section/after:size': len(U_BOOT_DATA),
4199 }
4200 self.assertEqual(expected, props)
4201
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004202 def testFitImageSubentryAlignment(self):
4203 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004204 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004205 entry_args = {
4206 'test-id': TEXT_DATA,
4207 }
4208 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4209 entry_args=entry_args)
4210 dtb = fdt.Fdt.FromData(data)
4211 dtb.Scan()
4212
4213 node = dtb.GetNode('/images/kernel')
4214 data = dtb.GetProps(node)["data"].bytes
4215 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004216 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4217 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004218 self.assertEqual(expected, data)
4219
4220 node = dtb.GetNode('/images/fdt-1')
4221 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004222 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4223 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004224 U_BOOT_DTB_DATA)
4225 self.assertEqual(expected, data)
4226
4227 def testFitExtblobMissingOk(self):
4228 """Test a FIT with a missing external blob that is allowed"""
4229 with test_util.capture_sys_output() as (stdout, stderr):
4230 self._DoTestFile('168_fit_missing_blob.dts',
4231 allow_missing=True)
4232 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004233 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004234
Simon Glass21db0ff2020-09-01 05:13:54 -06004235 def testBlobNamedByArgMissing(self):
4236 """Test handling of a missing entry arg"""
4237 with self.assertRaises(ValueError) as e:
4238 self._DoReadFile('068_blob_named_by_arg.dts')
4239 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4240 str(e.exception))
4241
Simon Glass559c4de2020-09-01 05:13:58 -06004242 def testPackBl31(self):
4243 """Test that an image with an ATF BL31 binary can be created"""
4244 data = self._DoReadFile('169_atf_bl31.dts')
4245 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4246
Samuel Holland9d8cc632020-10-21 21:12:15 -05004247 def testPackScp(self):
4248 """Test that an image with an SCP binary can be created"""
4249 data = self._DoReadFile('172_scp.dts')
4250 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4251
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004252 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004253 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004254 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004255 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004256 """Check the FDT nodes
4257
4258 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004259 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004260 expected_data: Expected contents of 'data' property
4261 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004262 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004263 fnode = dtb.GetNode('/images/%s' % name)
4264 self.assertIsNotNone(fnode)
4265 self.assertEqual({'description','type', 'compression', 'data'},
4266 set(fnode.props.keys()))
4267 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004268 description = (
4269 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4270 'fdt-%s.dtb' % val
4271 )
4272 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004273 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004274
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004275 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004276 """Check the configuration nodes
4277
4278 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004279 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004280 expected_data: Expected contents of 'data' property
4281 """
4282 cnode = dtb.GetNode('/configurations')
4283 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004284 default = (
4285 'config-2' if len(val) == 1 else
4286 'config-test-fdt2'
4287 )
4288 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004289
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004290 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004291 fnode = dtb.GetNode('/configurations/%s' % name)
4292 self.assertIsNotNone(fnode)
4293 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4294 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004295 description = (
4296 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4297 'conf-%s.dtb' % val
4298 )
4299 self.assertEqual(description, fnode.props['description'].value)
4300 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004301
4302 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004303 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004304 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004305 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004306 if use_fdt_list:
4307 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004308 if default_dt:
4309 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004310 if use_fdt_list:
4311 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004312 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004313 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004314 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004315 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004316 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4317 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4318
4319 dtb = fdt.Fdt.FromData(fit_data)
4320 dtb.Scan()
4321 fnode = dtb.GetNode('/images/kernel')
4322 self.assertIn('data', fnode.props)
4323
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004324 if use_seq_num == True:
4325 # Check all the properties in fdt-1 and fdt-2
4326 _CheckFdt('1', TEST_FDT1_DATA)
4327 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004328
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004329 # Check configurations
4330 _CheckConfig('1', TEST_FDT1_DATA)
4331 _CheckConfig('2', TEST_FDT2_DATA)
4332 else:
4333 # Check all the properties in fdt-1 and fdt-2
4334 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4335 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4336
4337 # Check configurations
4338 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4339 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004340
Simon Glasscd2783e2024-07-20 11:49:46 +01004341 def testFitFdt(self):
4342 """Test an image with an FIT with multiple FDT images"""
4343 self.CheckFitFdt()
4344
Simon Glassa435cd12020-09-01 05:13:59 -06004345 def testFitFdtMissingList(self):
4346 """Test handling of a missing 'of-list' entry arg"""
4347 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004348 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004349 self.assertIn("Generator node requires 'of-list' entry argument",
4350 str(e.exception))
4351
4352 def testFitFdtEmptyList(self):
4353 """Test handling of an empty 'of-list' entry arg"""
4354 entry_args = {
4355 'of-list': '',
4356 }
4357 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4358
4359 def testFitFdtMissingProp(self):
4360 """Test handling of a missing 'fit,fdt-list' property"""
4361 with self.assertRaises(ValueError) as e:
4362 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4363 self.assertIn("Generator node requires 'fit,fdt-list' property",
4364 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004365
Simon Glass1032acc2020-09-06 10:39:08 -06004366 def testFitFdtMissing(self):
4367 """Test handling of a missing 'default-dt' entry arg"""
4368 entry_args = {
4369 'of-list': 'test-fdt1 test-fdt2',
4370 }
4371 with self.assertRaises(ValueError) as e:
4372 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004373 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004374 entry_args=entry_args,
4375 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4376 self.assertIn("Generated 'default' node requires default-dt entry argument",
4377 str(e.exception))
4378
4379 def testFitFdtNotInList(self):
4380 """Test handling of a default-dt that is not in the of-list"""
4381 entry_args = {
4382 'of-list': 'test-fdt1 test-fdt2',
4383 'default-dt': 'test-fdt3',
4384 }
4385 with self.assertRaises(ValueError) as e:
4386 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004387 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004388 entry_args=entry_args,
4389 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4390 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4391 str(e.exception))
4392
Simon Glassa820af72020-09-06 10:39:09 -06004393 def testFitExtblobMissingHelp(self):
4394 """Test display of help messages when an external blob is missing"""
4395 control.missing_blob_help = control._ReadMissingBlobHelp()
4396 control.missing_blob_help['wibble'] = 'Wibble test'
4397 control.missing_blob_help['another'] = 'Another test'
4398 with test_util.capture_sys_output() as (stdout, stderr):
4399 self._DoTestFile('168_fit_missing_blob.dts',
4400 allow_missing=True)
4401 err = stderr.getvalue()
4402
4403 # We can get the tag from the name, the type or the missing-msg
4404 # property. Check all three.
4405 self.assertIn('You may need to build ARM Trusted', err)
4406 self.assertIn('Wibble test', err)
4407 self.assertIn('Another test', err)
4408
Simon Glass6f1f4d42020-09-06 10:35:32 -06004409 def testMissingBlob(self):
4410 """Test handling of a blob containing a missing file"""
4411 with self.assertRaises(ValueError) as e:
4412 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4413 self.assertIn("Filename 'missing' not found in input path",
4414 str(e.exception))
4415
Simon Glassa0729502020-09-06 10:35:33 -06004416 def testEnvironment(self):
4417 """Test adding a U-Boot environment"""
4418 data = self._DoReadFile('174_env.dts')
4419 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4420 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4421 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4422 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4423 env)
4424
4425 def testEnvironmentNoSize(self):
4426 """Test that a missing 'size' property is detected"""
4427 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004428 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004429 self.assertIn("'u-boot-env' entry must have a size property",
4430 str(e.exception))
4431
4432 def testEnvironmentTooSmall(self):
4433 """Test handling of an environment that does not fit"""
4434 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004435 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004436
4437 # checksum, start byte, environment with \0 terminator, final \0
4438 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4439 short = need - 0x8
4440 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4441 str(e.exception))
4442
Simon Glassd1fdf752020-10-26 17:40:01 -06004443 def testSkipAtStart(self):
4444 """Test handling of skip-at-start section"""
4445 data = self._DoReadFile('177_skip_at_start.dts')
4446 self.assertEqual(U_BOOT_DATA, data)
4447
4448 image = control.images['image']
4449 entries = image.GetEntries()
4450 section = entries['section']
4451 self.assertEqual(0, section.offset)
4452 self.assertEqual(len(U_BOOT_DATA), section.size)
4453 self.assertEqual(U_BOOT_DATA, section.GetData())
4454
4455 entry = section.GetEntries()['u-boot']
4456 self.assertEqual(16, entry.offset)
4457 self.assertEqual(len(U_BOOT_DATA), entry.size)
4458 self.assertEqual(U_BOOT_DATA, entry.data)
4459
4460 def testSkipAtStartPad(self):
4461 """Test handling of skip-at-start section with padded entry"""
4462 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004463 before = tools.get_bytes(0, 8)
4464 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004465 all = before + U_BOOT_DATA + after
4466 self.assertEqual(all, data)
4467
4468 image = control.images['image']
4469 entries = image.GetEntries()
4470 section = entries['section']
4471 self.assertEqual(0, section.offset)
4472 self.assertEqual(len(all), section.size)
4473 self.assertEqual(all, section.GetData())
4474
4475 entry = section.GetEntries()['u-boot']
4476 self.assertEqual(16, entry.offset)
4477 self.assertEqual(len(all), entry.size)
4478 self.assertEqual(U_BOOT_DATA, entry.data)
4479
4480 def testSkipAtStartSectionPad(self):
4481 """Test handling of skip-at-start section with padding"""
4482 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004483 before = tools.get_bytes(0, 8)
4484 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004485 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004486 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004487
4488 image = control.images['image']
4489 entries = image.GetEntries()
4490 section = entries['section']
4491 self.assertEqual(0, section.offset)
4492 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004493 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004494 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004495
4496 entry = section.GetEntries()['u-boot']
4497 self.assertEqual(16, entry.offset)
4498 self.assertEqual(len(U_BOOT_DATA), entry.size)
4499 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004500
Simon Glassbb395742020-10-26 17:40:14 -06004501 def testSectionPad(self):
4502 """Testing padding with sections"""
4503 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004504 expected = (tools.get_bytes(ord('&'), 3) +
4505 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004506 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004507 tools.get_bytes(ord('!'), 1) +
4508 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004509 self.assertEqual(expected, data)
4510
4511 def testSectionAlign(self):
4512 """Testing alignment with sections"""
4513 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4514 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004515 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004516 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004517 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004518 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004519 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4520 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004521 self.assertEqual(expected, data)
4522
Simon Glassd92c8362020-10-26 17:40:25 -06004523 def testCompressImage(self):
4524 """Test compression of the entire image"""
4525 self._CheckLz4()
4526 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4527 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4528 dtb = fdt.Fdt(out_dtb_fname)
4529 dtb.Scan()
4530 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4531 'uncomp-size'])
4532 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004533 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004534
4535 # Do a sanity check on various fields
4536 image = control.images['image']
4537 entries = image.GetEntries()
4538 self.assertEqual(2, len(entries))
4539
4540 entry = entries['blob']
4541 self.assertEqual(COMPRESS_DATA, entry.data)
4542 self.assertEqual(len(COMPRESS_DATA), entry.size)
4543
4544 entry = entries['u-boot']
4545 self.assertEqual(U_BOOT_DATA, entry.data)
4546 self.assertEqual(len(U_BOOT_DATA), entry.size)
4547
4548 self.assertEqual(len(data), image.size)
4549 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4550 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4551 orig = self._decompress(image.data)
4552 self.assertEqual(orig, image.uncomp_data)
4553
4554 expected = {
4555 'blob:offset': 0,
4556 'blob:size': len(COMPRESS_DATA),
4557 'u-boot:offset': len(COMPRESS_DATA),
4558 'u-boot:size': len(U_BOOT_DATA),
4559 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4560 'offset': 0,
4561 'image-pos': 0,
4562 'size': len(data),
4563 }
4564 self.assertEqual(expected, props)
4565
4566 def testCompressImageLess(self):
4567 """Test compression where compression reduces the image size"""
4568 self._CheckLz4()
4569 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4570 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4571 dtb = fdt.Fdt(out_dtb_fname)
4572 dtb.Scan()
4573 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4574 'uncomp-size'])
4575 orig = self._decompress(data)
4576
Brandon Maiera657bc62024-06-04 16:16:05 +00004577 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004578
4579 # Do a sanity check on various fields
4580 image = control.images['image']
4581 entries = image.GetEntries()
4582 self.assertEqual(2, len(entries))
4583
4584 entry = entries['blob']
4585 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4586 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4587
4588 entry = entries['u-boot']
4589 self.assertEqual(U_BOOT_DATA, entry.data)
4590 self.assertEqual(len(U_BOOT_DATA), entry.size)
4591
4592 self.assertEqual(len(data), image.size)
4593 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4594 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4595 image.uncomp_size)
4596 orig = self._decompress(image.data)
4597 self.assertEqual(orig, image.uncomp_data)
4598
4599 expected = {
4600 'blob:offset': 0,
4601 'blob:size': len(COMPRESS_DATA_BIG),
4602 'u-boot:offset': len(COMPRESS_DATA_BIG),
4603 'u-boot:size': len(U_BOOT_DATA),
4604 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4605 'offset': 0,
4606 'image-pos': 0,
4607 'size': len(data),
4608 }
4609 self.assertEqual(expected, props)
4610
4611 def testCompressSectionSize(self):
4612 """Test compression of a section with a fixed size"""
4613 self._CheckLz4()
4614 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4615 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4616 dtb = fdt.Fdt(out_dtb_fname)
4617 dtb.Scan()
4618 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4619 'uncomp-size'])
Jiaxun Yangc6931742025-04-10 06:43:03 -06004620 data = data[:0x30]
4621 data = data.rstrip(b'\xff')
Simon Glassd92c8362020-10-26 17:40:25 -06004622 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004623 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004624 expected = {
4625 'section/blob:offset': 0,
4626 'section/blob:size': len(COMPRESS_DATA),
4627 'section/u-boot:offset': len(COMPRESS_DATA),
4628 'section/u-boot:size': len(U_BOOT_DATA),
4629 'section:offset': 0,
4630 'section:image-pos': 0,
4631 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4632 'section:size': 0x30,
4633 'offset': 0,
4634 'image-pos': 0,
4635 'size': 0x30,
4636 }
4637 self.assertEqual(expected, props)
4638
4639 def testCompressSection(self):
4640 """Test compression of a section with no fixed size"""
4641 self._CheckLz4()
4642 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4643 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4644 dtb = fdt.Fdt(out_dtb_fname)
4645 dtb.Scan()
4646 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4647 'uncomp-size'])
4648 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004649 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004650 expected = {
4651 'section/blob:offset': 0,
4652 'section/blob:size': len(COMPRESS_DATA),
4653 'section/u-boot:offset': len(COMPRESS_DATA),
4654 'section/u-boot:size': len(U_BOOT_DATA),
4655 'section:offset': 0,
4656 'section:image-pos': 0,
4657 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4658 'section:size': len(data),
4659 'offset': 0,
4660 'image-pos': 0,
4661 'size': len(data),
4662 }
4663 self.assertEqual(expected, props)
4664
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004665 def testLz4Missing(self):
4666 """Test that binman still produces an image if lz4 is missing"""
4667 with test_util.capture_sys_output() as (_, stderr):
4668 self._DoTestFile('185_compress_section.dts',
4669 force_missing_bintools='lz4')
4670 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004671 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004672
Simon Glassd92c8362020-10-26 17:40:25 -06004673 def testCompressExtra(self):
4674 """Test compression of a section with no fixed size"""
4675 self._CheckLz4()
4676 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4677 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4678 dtb = fdt.Fdt(out_dtb_fname)
4679 dtb.Scan()
4680 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4681 'uncomp-size'])
4682
4683 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004684 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004685 rest = base[len(U_BOOT_DATA):]
4686
4687 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004688 bintool = self.comp_bintools['lz4']
4689 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004690 data1 = rest[:len(expect1)]
4691 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004692 self.assertEqual(expect1, data1)
4693 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004694 rest1 = rest[len(expect1):]
4695
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004696 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004697 data2 = rest1[:len(expect2)]
4698 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004699 self.assertEqual(expect2, data2)
4700 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004701 rest2 = rest1[len(expect2):]
4702
4703 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4704 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004705 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004706
Brandon Maiera657bc62024-06-04 16:16:05 +00004707 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004708
4709 self.maxDiff = None
4710 expected = {
4711 'u-boot:offset': 0,
4712 'u-boot:image-pos': 0,
4713 'u-boot:size': len(U_BOOT_DATA),
4714
4715 'base:offset': len(U_BOOT_DATA),
4716 'base:image-pos': len(U_BOOT_DATA),
4717 'base:size': len(data) - len(U_BOOT_DATA),
4718 'base/u-boot:offset': 0,
4719 'base/u-boot:image-pos': len(U_BOOT_DATA),
4720 'base/u-boot:size': len(U_BOOT_DATA),
4721 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4722 len(expect2),
4723 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4724 len(expect2),
4725 'base/u-boot2:size': len(U_BOOT_DATA),
4726
4727 'base/section:offset': len(U_BOOT_DATA),
4728 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4729 'base/section:size': len(expect1),
4730 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4731 'base/section/blob:offset': 0,
4732 'base/section/blob:size': len(COMPRESS_DATA),
4733 'base/section/u-boot:offset': len(COMPRESS_DATA),
4734 'base/section/u-boot:size': len(U_BOOT_DATA),
4735
4736 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4737 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4738 'base/section2:size': len(expect2),
4739 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4740 'base/section2/blob:offset': 0,
4741 'base/section2/blob:size': len(COMPRESS_DATA),
4742 'base/section2/blob2:offset': len(COMPRESS_DATA),
4743 'base/section2/blob2:size': len(COMPRESS_DATA),
4744
4745 'offset': 0,
4746 'image-pos': 0,
4747 'size': len(data),
4748 }
4749 self.assertEqual(expected, props)
4750
Simon Glassecbe4732021-01-06 21:35:15 -07004751 def testSymbolsSubsection(self):
4752 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004753 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004754
Simon Glass3fb25402021-01-06 21:35:16 -07004755 def testReadImageEntryArg(self):
4756 """Test reading an image that would need an entry arg to generate"""
4757 entry_args = {
4758 'cros-ec-rw-path': 'ecrw.bin',
4759 }
4760 data = self.data = self._DoReadFileDtb(
4761 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4762 entry_args=entry_args)
4763
Simon Glass80025522022-01-29 14:14:04 -07004764 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004765 orig_image = control.images['image']
4766
4767 # This should not generate an error about the missing 'cros-ec-rw-path'
4768 # since we are reading the image from a file. Compare with
4769 # testEntryArgsRequired()
4770 image = Image.FromFile(image_fname)
4771 self.assertEqual(orig_image.GetEntries().keys(),
4772 image.GetEntries().keys())
4773
Simon Glassa2af7302021-01-06 21:35:18 -07004774 def testFilesAlign(self):
4775 """Test alignment with files"""
4776 data = self._DoReadFile('190_files_align.dts')
4777
4778 # The first string is 15 bytes so will align to 16
4779 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4780 self.assertEqual(expect, data)
4781
Simon Glassdb84b562021-01-06 21:35:19 -07004782 def testReadImageSkip(self):
4783 """Test reading an image and accessing its FDT map"""
4784 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004785 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004786 orig_image = control.images['image']
4787 image = Image.FromFile(image_fname)
4788 self.assertEqual(orig_image.GetEntries().keys(),
4789 image.GetEntries().keys())
4790
4791 orig_entry = orig_image.GetEntries()['fdtmap']
4792 entry = image.GetEntries()['fdtmap']
4793 self.assertEqual(orig_entry.offset, entry.offset)
4794 self.assertEqual(orig_entry.size, entry.size)
Simon Glassed836ac2025-02-26 09:26:17 -07004795 self.assertEqual((1 << 32) - 0x400 + 16, entry.image_pos)
Simon Glassdb84b562021-01-06 21:35:19 -07004796
4797 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4798
Brandon Maiera657bc62024-06-04 16:16:05 +00004799 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004800
Simon Glassc98de972021-03-18 20:24:57 +13004801 def testTplNoDtb(self):
4802 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004803 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004804 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4805 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4806 data[:len(U_BOOT_TPL_NODTB_DATA)])
4807
Simon Glass63f41d42021-03-18 20:24:58 +13004808 def testTplBssPad(self):
4809 """Test that we can pad TPL's BSS with zeros"""
4810 # ELF file with a '__bss_size' symbol
4811 self._SetupTplElf()
4812 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004813 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004814 data)
4815
4816 def testTplBssPadMissing(self):
4817 """Test that a missing symbol is detected"""
4818 self._SetupTplElf('u_boot_ucode_ptr')
4819 with self.assertRaises(ValueError) as e:
4820 self._DoReadFile('193_tpl_bss_pad.dts')
4821 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4822 str(e.exception))
4823
Simon Glass718b5292021-03-18 20:25:07 +13004824 def checkDtbSizes(self, data, pad_len, start):
4825 """Check the size arguments in a dtb embedded in an image
4826
4827 Args:
4828 data: The image data
4829 pad_len: Length of the pad section in the image, in bytes
4830 start: Start offset of the devicetree to examine, within the image
4831
4832 Returns:
4833 Size of the devicetree in bytes
4834 """
4835 dtb_data = data[start:]
4836 dtb = fdt.Fdt.FromData(dtb_data)
4837 fdt_size = dtb.GetFdtObj().totalsize()
4838 dtb.Scan()
4839 props = self._GetPropTree(dtb, 'size')
4840 self.assertEqual({
4841 'size': len(data),
4842 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4843 'u-boot-spl/u-boot-spl-dtb:size': 801,
4844 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4845 'u-boot-spl:size': 860,
4846 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4847 'u-boot/u-boot-dtb:size': 781,
4848 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4849 'u-boot:size': 827,
4850 }, props)
4851 return fdt_size
4852
4853 def testExpanded(self):
4854 """Test that an expanded entry type is selected when needed"""
4855 self._SetupSplElf()
4856 self._SetupTplElf()
4857
4858 # SPL has a devicetree, TPL does not
4859 entry_args = {
4860 'spl-dtb': '1',
4861 'spl-bss-pad': 'y',
4862 'tpl-dtb': '',
4863 }
4864 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4865 entry_args=entry_args)
4866 image = control.images['image']
4867 entries = image.GetEntries()
4868 self.assertEqual(3, len(entries))
4869
4870 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4871 self.assertIn('u-boot', entries)
4872 entry = entries['u-boot']
4873 self.assertEqual('u-boot-expanded', entry.etype)
4874 subent = entry.GetEntries()
4875 self.assertEqual(2, len(subent))
4876 self.assertIn('u-boot-nodtb', subent)
4877 self.assertIn('u-boot-dtb', subent)
4878
4879 # Second, u-boot-spl, which should be expanded into three parts
4880 self.assertIn('u-boot-spl', entries)
4881 entry = entries['u-boot-spl']
4882 self.assertEqual('u-boot-spl-expanded', entry.etype)
4883 subent = entry.GetEntries()
4884 self.assertEqual(3, len(subent))
4885 self.assertIn('u-boot-spl-nodtb', subent)
4886 self.assertIn('u-boot-spl-bss-pad', subent)
4887 self.assertIn('u-boot-spl-dtb', subent)
4888
4889 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4890 # devicetree
4891 self.assertIn('u-boot-tpl', entries)
4892 entry = entries['u-boot-tpl']
4893 self.assertEqual('u-boot-tpl', entry.etype)
4894 self.assertEqual(None, entry.GetEntries())
4895
4896 def testExpandedTpl(self):
4897 """Test that an expanded entry type is selected for TPL when needed"""
4898 self._SetupTplElf()
4899
4900 entry_args = {
4901 'tpl-bss-pad': 'y',
4902 'tpl-dtb': 'y',
4903 }
4904 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4905 entry_args=entry_args)
4906 image = control.images['image']
4907 entries = image.GetEntries()
4908 self.assertEqual(1, len(entries))
4909
4910 # We only have u-boot-tpl, which be expanded
4911 self.assertIn('u-boot-tpl', entries)
4912 entry = entries['u-boot-tpl']
4913 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4914 subent = entry.GetEntries()
4915 self.assertEqual(3, len(subent))
4916 self.assertIn('u-boot-tpl-nodtb', subent)
4917 self.assertIn('u-boot-tpl-bss-pad', subent)
4918 self.assertIn('u-boot-tpl-dtb', subent)
4919
4920 def testExpandedNoPad(self):
4921 """Test an expanded entry without BSS pad enabled"""
4922 self._SetupSplElf()
4923 self._SetupTplElf()
4924
4925 # SPL has a devicetree, TPL does not
4926 entry_args = {
4927 'spl-dtb': 'something',
4928 'spl-bss-pad': 'n',
4929 'tpl-dtb': '',
4930 }
4931 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4932 entry_args=entry_args)
4933 image = control.images['image']
4934 entries = image.GetEntries()
4935
4936 # Just check u-boot-spl, which should be expanded into two parts
4937 self.assertIn('u-boot-spl', entries)
4938 entry = entries['u-boot-spl']
4939 self.assertEqual('u-boot-spl-expanded', entry.etype)
4940 subent = entry.GetEntries()
4941 self.assertEqual(2, len(subent))
4942 self.assertIn('u-boot-spl-nodtb', subent)
4943 self.assertIn('u-boot-spl-dtb', subent)
4944
4945 def testExpandedTplNoPad(self):
4946 """Test that an expanded entry type with padding disabled in TPL"""
4947 self._SetupTplElf()
4948
4949 entry_args = {
4950 'tpl-bss-pad': '',
4951 'tpl-dtb': 'y',
4952 }
4953 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4954 entry_args=entry_args)
4955 image = control.images['image']
4956 entries = image.GetEntries()
4957 self.assertEqual(1, len(entries))
4958
4959 # We only have u-boot-tpl, which be expanded
4960 self.assertIn('u-boot-tpl', entries)
4961 entry = entries['u-boot-tpl']
4962 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4963 subent = entry.GetEntries()
4964 self.assertEqual(2, len(subent))
4965 self.assertIn('u-boot-tpl-nodtb', subent)
4966 self.assertIn('u-boot-tpl-dtb', subent)
4967
4968 def testFdtInclude(self):
4969 """Test that an Fdt is update within all binaries"""
4970 self._SetupSplElf()
4971 self._SetupTplElf()
4972
4973 # SPL has a devicetree, TPL does not
4974 self.maxDiff = None
4975 entry_args = {
4976 'spl-dtb': '1',
4977 'spl-bss-pad': 'y',
4978 'tpl-dtb': '',
4979 }
4980 # Build the image. It includes two separate devicetree binaries, each
4981 # with their own contents, but all contain the binman definition.
4982 data = self._DoReadFileDtb(
4983 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4984 update_dtb=True, entry_args=entry_args)[0]
4985 pad_len = 10
4986
4987 # Check the U-Boot dtb
4988 start = len(U_BOOT_NODTB_DATA)
4989 fdt_size = self.checkDtbSizes(data, pad_len, start)
4990
4991 # Now check SPL
4992 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4993 fdt_size = self.checkDtbSizes(data, pad_len, start)
4994
4995 # TPL has no devicetree
4996 start += fdt_size + len(U_BOOT_TPL_DATA)
4997 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004998
Simon Glass7098b7f2021-03-21 18:24:30 +13004999 def testSymbolsExpanded(self):
5000 """Test binman can assign symbols in expanded entries"""
5001 entry_args = {
5002 'spl-dtb': '1',
5003 }
5004 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
5005 U_BOOT_SPL_DTB_DATA, 0x38,
5006 entry_args=entry_args, use_expanded=True)
5007
Simon Glasse1915782021-03-21 18:24:31 +13005008 def testCollection(self):
5009 """Test a collection"""
5010 data = self._DoReadFile('198_collection.dts')
5011 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07005012 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5013 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13005014 data)
5015
Simon Glass27a7f772021-03-21 18:24:32 +13005016 def testCollectionSection(self):
5017 """Test a collection where a section must be built first"""
5018 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005019 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005020 # building the contents, producing an error is anything is still
5021 # missing.
5022 data = self._DoReadFile('199_collection_section.dts')
5023 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005024 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5025 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005026 data)
5027
Simon Glassf427c5f2021-03-21 18:24:33 +13005028 def testAlignDefault(self):
5029 """Test that default alignment works on sections"""
5030 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005031 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005032 U_BOOT_DATA)
5033 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005034 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005035 # No alignment within the nested section
5036 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5037 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005038 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005039 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005040
Bin Mengc0b15742021-05-10 20:23:33 +08005041 def testPackOpenSBI(self):
5042 """Test that an image with an OpenSBI binary can be created"""
5043 data = self._DoReadFile('201_opensbi.dts')
5044 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5045
Simon Glass76f496d2021-07-06 10:36:37 -06005046 def testSectionsSingleThread(self):
5047 """Test sections without multithreading"""
5048 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005049 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5050 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5051 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005052 self.assertEqual(expected, data)
5053
5054 def testThreadTimeout(self):
5055 """Test handling a thread that takes too long"""
5056 with self.assertRaises(ValueError) as e:
5057 self._DoTestFile('202_section_timeout.dts',
5058 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005059 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005060
Simon Glass748a1d42021-07-06 10:36:41 -06005061 def testTiming(self):
5062 """Test output of timing information"""
5063 data = self._DoReadFile('055_sections.dts')
5064 with test_util.capture_sys_output() as (stdout, stderr):
5065 state.TimingShow()
5066 self.assertIn('read:', stdout.getvalue())
5067 self.assertIn('compress:', stdout.getvalue())
5068
Simon Glassadfb8492021-11-03 21:09:18 -06005069 def testUpdateFdtInElf(self):
5070 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005071 if not elf.ELF_TOOLS:
5072 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005073 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5074 outfile = os.path.join(self._indir, 'u-boot.out')
5075 begin_sym = 'dtb_embed_begin'
5076 end_sym = 'dtb_embed_end'
5077 retcode = self._DoTestFile(
5078 '060_fdt_update.dts', update_dtb=True,
5079 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5080 self.assertEqual(0, retcode)
5081
5082 # Check that the output file does in fact contact a dtb with the binman
5083 # definition in the correct place
5084 syms = elf.GetSymbolFileOffset(infile,
5085 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005086 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005087 dtb_data = data[syms['dtb_embed_begin'].offset:
5088 syms['dtb_embed_end'].offset]
5089
5090 dtb = fdt.Fdt.FromData(dtb_data)
5091 dtb.Scan()
5092 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5093 self.assertEqual({
5094 'image-pos': 0,
5095 'offset': 0,
5096 '_testing:offset': 32,
5097 '_testing:size': 2,
5098 '_testing:image-pos': 32,
5099 'section@0/u-boot:offset': 0,
5100 'section@0/u-boot:size': len(U_BOOT_DATA),
5101 'section@0/u-boot:image-pos': 0,
5102 'section@0:offset': 0,
5103 'section@0:size': 16,
5104 'section@0:image-pos': 0,
5105
5106 'section@1/u-boot:offset': 0,
5107 'section@1/u-boot:size': len(U_BOOT_DATA),
5108 'section@1/u-boot:image-pos': 16,
5109 'section@1:offset': 16,
5110 'section@1:size': 16,
5111 'section@1:image-pos': 16,
5112 'size': 40
5113 }, props)
5114
5115 def testUpdateFdtInElfInvalid(self):
5116 """Test that invalid args are detected with --update-fdt-in-elf"""
5117 with self.assertRaises(ValueError) as e:
5118 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5119 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5120 str(e.exception))
5121
5122 def testUpdateFdtInElfNoSyms(self):
5123 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005124 if not elf.ELF_TOOLS:
5125 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005126 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5127 outfile = ''
5128 begin_sym = 'wrong_begin'
5129 end_sym = 'wrong_end'
5130 with self.assertRaises(ValueError) as e:
5131 self._DoTestFile(
5132 '060_fdt_update.dts',
5133 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5134 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5135 str(e.exception))
5136
5137 def testUpdateFdtInElfTooSmall(self):
5138 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005139 if not elf.ELF_TOOLS:
5140 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005141 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5142 outfile = os.path.join(self._indir, 'u-boot.out')
5143 begin_sym = 'dtb_embed_begin'
5144 end_sym = 'dtb_embed_end'
5145 with self.assertRaises(ValueError) as e:
5146 self._DoTestFile(
5147 '060_fdt_update.dts', update_dtb=True,
5148 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5149 self.assertRegex(
5150 str(e.exception),
5151 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5152
Simon Glass88e04da2021-11-23 11:03:42 -07005153 def testVersion(self):
5154 """Test we can get the binman version"""
5155 version = '(unreleased)'
5156 self.assertEqual(version, state.GetVersion(self._indir))
5157
5158 with self.assertRaises(SystemExit):
5159 with test_util.capture_sys_output() as (_, stderr):
5160 self._DoBinman('-V')
5161 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5162
5163 # Try running the tool too, just to be safe
5164 result = self._RunBinman('-V')
5165 self.assertEqual('Binman %s\n' % version, result.stderr)
5166
5167 # Set up a version file to make sure that works
5168 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005169 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005170 binary=False)
5171 self.assertEqual(version, state.GetVersion(self._indir))
5172
Simon Glass637958f2021-11-23 21:09:50 -07005173 def testAltFormat(self):
5174 """Test that alternative formats can be used to extract"""
5175 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5176
5177 try:
5178 tmpdir, updated_fname = self._SetupImageInTmpdir()
5179 with test_util.capture_sys_output() as (stdout, _):
5180 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5181 self.assertEqual(
5182 '''Flag (-F) Entry type Description
5183fdt fdtmap Extract the devicetree blob from the fdtmap
5184''',
5185 stdout.getvalue())
5186
5187 dtb = os.path.join(tmpdir, 'fdt.dtb')
5188 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5189 dtb, 'fdtmap')
5190
5191 # Check that we can read it and it can be scanning, meaning it does
5192 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005193 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005194 dtb = fdt.Fdt.FromData(data)
5195 dtb.Scan()
5196
5197 # Now check u-boot which has no alt_format
5198 fname = os.path.join(tmpdir, 'fdt.dtb')
5199 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5200 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005201 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005202 self.assertEqual(U_BOOT_DATA, data)
5203
5204 finally:
5205 shutil.rmtree(tmpdir)
5206
Simon Glass0b00ae62021-11-23 21:09:52 -07005207 def testExtblobList(self):
5208 """Test an image with an external blob list"""
5209 data = self._DoReadFile('215_blob_ext_list.dts')
5210 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5211
5212 def testExtblobListMissing(self):
5213 """Test an image with a missing external blob"""
5214 with self.assertRaises(ValueError) as e:
5215 self._DoReadFile('216_blob_ext_list_missing.dts')
5216 self.assertIn("Filename 'missing-file' not found in input path",
5217 str(e.exception))
5218
5219 def testExtblobListMissingOk(self):
5220 """Test an image with an missing external blob that is allowed"""
5221 with test_util.capture_sys_output() as (stdout, stderr):
5222 self._DoTestFile('216_blob_ext_list_missing.dts',
5223 allow_missing=True)
5224 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005225 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005226
Simon Glass3efb2972021-11-23 21:08:59 -07005227 def testFip(self):
5228 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5229 data = self._DoReadFile('203_fip.dts')
5230 hdr, fents = fip_util.decode_fip(data)
5231 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5232 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5233 self.assertEqual(0x123, hdr.flags)
5234
5235 self.assertEqual(2, len(fents))
5236
5237 fent = fents[0]
5238 self.assertEqual(
5239 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5240 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5241 self.assertEqual('soc-fw', fent.fip_type)
5242 self.assertEqual(0x88, fent.offset)
5243 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5244 self.assertEqual(0x123456789abcdef, fent.flags)
5245 self.assertEqual(ATF_BL31_DATA, fent.data)
5246 self.assertEqual(True, fent.valid)
5247
5248 fent = fents[1]
5249 self.assertEqual(
5250 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5251 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5252 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5253 self.assertEqual(0x8c, fent.offset)
5254 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5255 self.assertEqual(0, fent.flags)
5256 self.assertEqual(ATF_BL2U_DATA, fent.data)
5257 self.assertEqual(True, fent.valid)
5258
5259 def testFipOther(self):
5260 """Basic FIP with something that isn't a external blob"""
5261 data = self._DoReadFile('204_fip_other.dts')
5262 hdr, fents = fip_util.decode_fip(data)
5263
5264 self.assertEqual(2, len(fents))
5265 fent = fents[1]
5266 self.assertEqual('rot-cert', fent.fip_type)
5267 self.assertEqual(b'aa', fent.data)
5268
Simon Glass3efb2972021-11-23 21:08:59 -07005269 def testFipNoType(self):
5270 """FIP with an entry of an unknown type"""
5271 with self.assertRaises(ValueError) as e:
5272 self._DoReadFile('205_fip_no_type.dts')
5273 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5274 str(e.exception))
5275
5276 def testFipUuid(self):
5277 """Basic FIP with a manual uuid"""
5278 data = self._DoReadFile('206_fip_uuid.dts')
5279 hdr, fents = fip_util.decode_fip(data)
5280
5281 self.assertEqual(2, len(fents))
5282 fent = fents[1]
5283 self.assertEqual(None, fent.fip_type)
5284 self.assertEqual(
5285 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5286 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5287 fent.uuid)
5288 self.assertEqual(U_BOOT_DATA, fent.data)
5289
5290 def testFipLs(self):
5291 """Test listing a FIP"""
5292 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5293 hdr, fents = fip_util.decode_fip(data)
5294
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005295 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005296 try:
5297 tmpdir, updated_fname = self._SetupImageInTmpdir()
5298 with test_util.capture_sys_output() as (stdout, stderr):
5299 self._DoBinman('ls', '-i', updated_fname)
5300 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005301 if tmpdir:
5302 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005303 lines = stdout.getvalue().splitlines()
5304 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005305'Name Image-pos Size Entry-type Offset Uncomp-size',
5306'--------------------------------------------------------------',
5307'image 0 2d3 section 0',
5308' atf-fip 0 90 atf-fip 0',
5309' soc-fw 88 4 blob-ext 88',
5310' u-boot 8c 4 u-boot 8c',
5311' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005312]
5313 self.assertEqual(expected, lines)
5314
5315 image = control.images['image']
5316 entries = image.GetEntries()
5317 fdtmap = entries['fdtmap']
5318
5319 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5320 magic = fdtmap_data[:8]
5321 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005322 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005323
5324 fdt_data = fdtmap_data[16:]
5325 dtb = fdt.Fdt.FromData(fdt_data)
5326 dtb.Scan()
5327 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5328 self.assertEqual({
5329 'atf-fip/soc-fw:image-pos': 136,
5330 'atf-fip/soc-fw:offset': 136,
5331 'atf-fip/soc-fw:size': 4,
5332 'atf-fip/u-boot:image-pos': 140,
5333 'atf-fip/u-boot:offset': 140,
5334 'atf-fip/u-boot:size': 4,
5335 'atf-fip:image-pos': 0,
5336 'atf-fip:offset': 0,
5337 'atf-fip:size': 144,
5338 'image-pos': 0,
5339 'offset': 0,
5340 'fdtmap:image-pos': fdtmap.image_pos,
5341 'fdtmap:offset': fdtmap.offset,
5342 'fdtmap:size': len(fdtmap_data),
5343 'size': len(data),
5344 }, props)
5345
5346 def testFipExtractOneEntry(self):
5347 """Test extracting a single entry fron an FIP"""
5348 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005349 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005350 fname = os.path.join(self._indir, 'output.extact')
5351 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005352 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005353 self.assertEqual(U_BOOT_DATA, data)
5354
5355 def testFipReplace(self):
5356 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005357 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005358 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005359 updated_fname = tools.get_output_filename('image-updated.bin')
5360 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005361 entry_name = 'atf-fip/u-boot'
5362 control.WriteEntry(updated_fname, entry_name, expected,
5363 allow_resize=True)
5364 actual = control.ReadEntry(updated_fname, entry_name)
5365 self.assertEqual(expected, actual)
5366
Simon Glass80025522022-01-29 14:14:04 -07005367 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005368 hdr, fents = fip_util.decode_fip(new_data)
5369
5370 self.assertEqual(2, len(fents))
5371
5372 # Check that the FIP entry is updated
5373 fent = fents[1]
5374 self.assertEqual(0x8c, fent.offset)
5375 self.assertEqual(len(expected), fent.size)
5376 self.assertEqual(0, fent.flags)
5377 self.assertEqual(expected, fent.data)
5378 self.assertEqual(True, fent.valid)
5379
5380 def testFipMissing(self):
5381 with test_util.capture_sys_output() as (stdout, stderr):
5382 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5383 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005384 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005385
5386 def testFipSize(self):
5387 """Test a FIP with a size property"""
5388 data = self._DoReadFile('210_fip_size.dts')
5389 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5390 hdr, fents = fip_util.decode_fip(data)
5391 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5392 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5393
5394 self.assertEqual(1, len(fents))
5395
5396 fent = fents[0]
5397 self.assertEqual('soc-fw', fent.fip_type)
5398 self.assertEqual(0x60, fent.offset)
5399 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5400 self.assertEqual(ATF_BL31_DATA, fent.data)
5401 self.assertEqual(True, fent.valid)
5402
5403 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005404 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005405
5406 def testFipBadAlign(self):
5407 """Test that an invalid alignment value in a FIP is detected"""
5408 with self.assertRaises(ValueError) as e:
5409 self._DoTestFile('211_fip_bad_align.dts')
5410 self.assertIn(
5411 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5412 str(e.exception))
5413
5414 def testFipCollection(self):
5415 """Test using a FIP in a collection"""
5416 data = self._DoReadFile('212_fip_collection.dts')
5417 entry1 = control.images['image'].GetEntries()['collection']
5418 data1 = data[:entry1.size]
5419 hdr1, fents2 = fip_util.decode_fip(data1)
5420
5421 entry2 = control.images['image'].GetEntries()['atf-fip']
5422 data2 = data[entry2.offset:entry2.offset + entry2.size]
5423 hdr1, fents2 = fip_util.decode_fip(data2)
5424
5425 # The 'collection' entry should have U-Boot included at the end
5426 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5427 self.assertEqual(data1, data2 + U_BOOT_DATA)
5428 self.assertEqual(U_BOOT_DATA, data1[-4:])
5429
5430 # There should be a U-Boot after the final FIP
5431 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005432
Simon Glassccae6862022-01-12 13:10:35 -07005433 def testFakeBlob(self):
5434 """Test handling of faking an external blob"""
5435 with test_util.capture_sys_output() as (stdout, stderr):
5436 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5437 allow_fake_blobs=True)
5438 err = stderr.getvalue()
5439 self.assertRegex(
5440 err,
5441 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005442
Simon Glassceb5f912022-01-09 20:13:46 -07005443 def testExtblobListFaked(self):
5444 """Test an extblob with missing external blob that are faked"""
5445 with test_util.capture_sys_output() as (stdout, stderr):
5446 self._DoTestFile('216_blob_ext_list_missing.dts',
5447 allow_fake_blobs=True)
5448 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005449 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005450
Simon Glass162017b2022-01-09 20:13:57 -07005451 def testListBintools(self):
5452 args = ['tool', '--list']
5453 with test_util.capture_sys_output() as (stdout, _):
5454 self._DoBinman(*args)
5455 out = stdout.getvalue().splitlines()
5456 self.assertTrue(len(out) >= 2)
5457
5458 def testFetchBintools(self):
5459 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005460 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005461 raise urllib.error.URLError('my error')
5462
5463 args = ['tool']
5464 with self.assertRaises(ValueError) as e:
5465 self._DoBinman(*args)
5466 self.assertIn("Invalid arguments to 'tool' subcommand",
5467 str(e.exception))
5468
5469 args = ['tool', '--fetch']
5470 with self.assertRaises(ValueError) as e:
5471 self._DoBinman(*args)
5472 self.assertIn('Please specify bintools to fetch', str(e.exception))
5473
5474 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005475 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005476 side_effect=fail_download):
5477 with test_util.capture_sys_output() as (stdout, _):
5478 self._DoBinman(*args)
5479 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5480
Simon Glass620c4462022-01-09 20:14:11 -07005481 def testBintoolDocs(self):
5482 """Test for creation of bintool documentation"""
5483 with test_util.capture_sys_output() as (stdout, stderr):
5484 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5485 self.assertTrue(len(stdout.getvalue()) > 0)
5486
5487 def testBintoolDocsMissing(self):
5488 """Test handling of missing bintool documentation"""
5489 with self.assertRaises(ValueError) as e:
5490 with test_util.capture_sys_output() as (stdout, stderr):
5491 control.write_bintool_docs(
5492 control.bintool.Bintool.get_tool_list(), 'mkimage')
5493 self.assertIn('Documentation is missing for modules: mkimage',
5494 str(e.exception))
5495
Jan Kiszka58c407f2022-01-28 20:37:53 +01005496 def testListWithGenNode(self):
5497 """Check handling of an FDT map when the section cannot be found"""
5498 entry_args = {
5499 'of-list': 'test-fdt1 test-fdt2',
5500 }
5501 data = self._DoReadFileDtb(
5502 '219_fit_gennode.dts',
5503 entry_args=entry_args,
5504 use_real_dtb=True,
5505 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5506
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005507 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005508 try:
5509 tmpdir, updated_fname = self._SetupImageInTmpdir()
5510 with test_util.capture_sys_output() as (stdout, stderr):
5511 self._RunBinman('ls', '-i', updated_fname)
5512 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005513 if tmpdir:
5514 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005515
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005516 def testFitSubentryUsesBintool(self):
5517 """Test that binman FIT subentries can use bintools"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07005518 command.TEST_RESULT = self._HandleGbbCommand
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005519 entry_args = {
5520 'keydir': 'devkeys',
5521 'bmpblk': 'bmpblk.bin',
5522 }
5523 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5524 entry_args=entry_args)
5525
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005526 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5527 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005528 self.assertIn(expected, data)
5529
5530 def testFitSubentryMissingBintool(self):
5531 """Test that binman reports missing bintools for FIT subentries"""
5532 entry_args = {
5533 'keydir': 'devkeys',
5534 }
5535 with test_util.capture_sys_output() as (_, stderr):
5536 self._DoTestFile('220_fit_subentry_bintool.dts',
5537 force_missing_bintools='futility', entry_args=entry_args)
5538 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005539 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005540
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005541 def testFitSubentryHashSubnode(self):
5542 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005543 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005544 data, _, _, out_dtb_name = self._DoReadFileDtb(
5545 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5546
5547 mkimage_dtb = fdt.Fdt.FromData(data)
5548 mkimage_dtb.Scan()
5549 binman_dtb = fdt.Fdt(out_dtb_name)
5550 binman_dtb.Scan()
5551
5552 # Check that binman didn't add hash values
5553 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5554 self.assertNotIn('value', fnode.props)
5555
5556 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5557 self.assertNotIn('value', fnode.props)
5558
5559 # Check that mkimage added hash values
5560 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5561 self.assertIn('value', fnode.props)
5562
5563 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5564 self.assertIn('value', fnode.props)
5565
Roger Quadros5cdcea02022-02-19 20:50:04 +02005566 def testPackTeeOs(self):
5567 """Test that an image with an TEE binary can be created"""
5568 data = self._DoReadFile('222_tee_os.dts')
5569 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5570
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305571 def testPackTiDm(self):
5572 """Test that an image with a TI DM binary can be created"""
5573 data = self._DoReadFile('225_ti_dm.dts')
5574 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5575
Simon Glass912339f2022-02-08 11:50:03 -07005576 def testFitFdtOper(self):
5577 """Check handling of a specified FIT operation"""
5578 entry_args = {
5579 'of-list': 'test-fdt1 test-fdt2',
5580 'default-dt': 'test-fdt2',
5581 }
5582 self._DoReadFileDtb(
5583 '223_fit_fdt_oper.dts',
5584 entry_args=entry_args,
5585 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5586
5587 def testFitFdtBadOper(self):
5588 """Check handling of an FDT map when the section cannot be found"""
5589 with self.assertRaises(ValueError) as exc:
5590 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005591 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005592 str(exc.exception))
5593
Simon Glassdd156a42022-03-05 20:18:59 -07005594 def test_uses_expand_size(self):
5595 """Test that the 'expand-size' property cannot be used anymore"""
5596 with self.assertRaises(ValueError) as e:
5597 data = self._DoReadFile('225_expand_size_bad.dts')
5598 self.assertIn(
5599 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5600 str(e.exception))
5601
Simon Glass5f423422022-03-05 20:19:12 -07005602 def testFitSplitElf(self):
5603 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005604 if not elf.ELF_TOOLS:
5605 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005606 entry_args = {
5607 'of-list': 'test-fdt1 test-fdt2',
5608 'default-dt': 'test-fdt2',
5609 'atf-bl31-path': 'bl31.elf',
5610 'tee-os-path': 'tee.elf',
5611 }
5612 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5613 data = self._DoReadFileDtb(
5614 '226_fit_split_elf.dts',
5615 entry_args=entry_args,
5616 extra_indirs=[test_subdir])[0]
5617
5618 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5619 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5620
5621 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5622 'data', 'load'}
5623 dtb = fdt.Fdt.FromData(fit_data)
5624 dtb.Scan()
5625
5626 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5627 segments, entry = elf.read_loadable_segments(elf_data)
5628
5629 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005630 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005631
5632 atf1 = dtb.GetNode('/images/atf-1')
5633 _, start, data = segments[0]
5634 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5635 self.assertEqual(entry,
5636 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5637 self.assertEqual(start,
5638 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5639 self.assertEqual(data, atf1.props['data'].bytes)
5640
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005641 hash_node = atf1.FindNode('hash')
5642 self.assertIsNotNone(hash_node)
5643 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5644
Simon Glass5f423422022-03-05 20:19:12 -07005645 atf2 = dtb.GetNode('/images/atf-2')
5646 self.assertEqual(base_keys, atf2.props.keys())
5647 _, start, data = segments[1]
5648 self.assertEqual(start,
5649 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5650 self.assertEqual(data, atf2.props['data'].bytes)
5651
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005652 hash_node = atf2.FindNode('hash')
5653 self.assertIsNotNone(hash_node)
5654 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5655
5656 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5657 self.assertIsNotNone(hash_node)
5658 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5659
Simon Glass5f423422022-03-05 20:19:12 -07005660 conf = dtb.GetNode('/configurations')
5661 self.assertEqual({'default'}, conf.props.keys())
5662
5663 for subnode in conf.subnodes:
5664 self.assertEqual({'description', 'fdt', 'loadables'},
5665 subnode.props.keys())
5666 self.assertEqual(
5667 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5668 fdt_util.GetStringList(subnode, 'loadables'))
5669
5670 def _check_bad_fit(self, dts):
5671 """Check a bad FIT
5672
5673 This runs with the given dts and returns the assertion raised
5674
5675 Args:
5676 dts (str): dts filename to use
5677
5678 Returns:
5679 str: Assertion string raised
5680 """
5681 entry_args = {
5682 'of-list': 'test-fdt1 test-fdt2',
5683 'default-dt': 'test-fdt2',
5684 'atf-bl31-path': 'bl31.elf',
5685 'tee-os-path': 'tee.elf',
5686 }
5687 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5688 with self.assertRaises(ValueError) as exc:
5689 self._DoReadFileDtb(dts, entry_args=entry_args,
5690 extra_indirs=[test_subdir])[0]
5691 return str(exc.exception)
5692
5693 def testFitSplitElfBadElf(self):
5694 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005695 if not elf.ELF_TOOLS:
5696 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005697 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5698 entry_args = {
5699 'of-list': 'test-fdt1 test-fdt2',
5700 'default-dt': 'test-fdt2',
5701 'atf-bl31-path': 'bad.elf',
5702 'tee-os-path': 'tee.elf',
5703 }
5704 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5705 with self.assertRaises(ValueError) as exc:
5706 self._DoReadFileDtb(
5707 '226_fit_split_elf.dts',
5708 entry_args=entry_args,
5709 extra_indirs=[test_subdir])[0]
5710 self.assertIn(
5711 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5712 str(exc.exception))
5713
Simon Glass5f423422022-03-05 20:19:12 -07005714 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005715 """Test an split-elf FIT with a missing ELF file
5716
5717 Args:
5718 kwargs (dict of str): Arguments to pass to _DoTestFile()
5719
5720 Returns:
5721 tuple:
5722 str: stdout result
5723 str: stderr result
5724 """
Simon Glass5f423422022-03-05 20:19:12 -07005725 entry_args = {
5726 'of-list': 'test-fdt1 test-fdt2',
5727 'default-dt': 'test-fdt2',
5728 'atf-bl31-path': 'bl31.elf',
5729 'tee-os-path': 'missing.elf',
5730 }
5731 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5732 with test_util.capture_sys_output() as (stdout, stderr):
5733 self._DoTestFile(
5734 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005735 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5736 out = stdout.getvalue()
5737 err = stderr.getvalue()
5738 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005739
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005740 def testFitSplitElfBadDirective(self):
5741 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5742 if not elf.ELF_TOOLS:
5743 self.skipTest('Python elftools not available')
5744 err = self._check_bad_fit('227_fit_bad_dir.dts')
5745 self.assertIn(
5746 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5747 err)
5748
5749 def testFitSplitElfBadDirectiveConfig(self):
5750 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5751 if not elf.ELF_TOOLS:
5752 self.skipTest('Python elftools not available')
5753 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5754 self.assertEqual(
5755 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5756 err)
5757
5758
Simon Glass5f423422022-03-05 20:19:12 -07005759 def testFitSplitElfMissing(self):
5760 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005761 if not elf.ELF_TOOLS:
5762 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005763 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005764 self.assertRegex(
5765 err,
5766 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005767 self.assertNotRegex(out, '.*Faked blob.*')
5768 fname = tools.get_output_filename('binman-fake/missing.elf')
5769 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005770
5771 def testFitSplitElfFaked(self):
5772 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005773 if not elf.ELF_TOOLS:
5774 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005775 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005776 self.assertRegex(
5777 err,
5778 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005779 self.assertRegex(
5780 out,
5781 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5782 fname = tools.get_output_filename('binman-fake/missing.elf')
5783 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005784
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005785 def testMkimageMissingBlob(self):
5786 """Test using mkimage to build an image"""
5787 with test_util.capture_sys_output() as (stdout, stderr):
5788 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5789 allow_fake_blobs=True)
5790 err = stderr.getvalue()
5791 self.assertRegex(
5792 err,
5793 "Image '.*' has faked external blobs and is non-functional: .*")
5794
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005795 def testPreLoad(self):
5796 """Test an image with a pre-load header"""
5797 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005798 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005799 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005800 data = self._DoReadFileDtb(
5801 '230_pre_load.dts', entry_args=entry_args,
5802 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Paul HENRYS5cf82892025-02-24 22:20:55 +01005803
5804 image_fname = tools.get_output_filename('image.bin')
5805 is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
5806
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005807 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5808 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5809 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Paul HENRYS5cf82892025-02-24 22:20:55 +01005810 self.assertEqual(is_signed, True)
Simon Glasse2dfb962023-07-24 09:19:57 -06005811
5812 def testPreLoadNoKey(self):
5813 """Test an image with a pre-load heade0r with missing key"""
5814 with self.assertRaises(FileNotFoundError) as exc:
5815 self._DoReadFile('230_pre_load.dts')
5816 self.assertIn("No such file or directory: 'dev.key'",
5817 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005818
5819 def testPreLoadPkcs(self):
5820 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005821 entry_args = {
5822 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5823 }
5824 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5825 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005826 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5827 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5828 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5829
5830 def testPreLoadPss(self):
5831 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005832 entry_args = {
5833 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5834 }
5835 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5836 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005837 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5838 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5839 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5840
5841 def testPreLoadInvalidPadding(self):
5842 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005843 entry_args = {
5844 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5845 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005846 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005847 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5848 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005849
5850 def testPreLoadInvalidSha(self):
5851 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005852 entry_args = {
5853 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5854 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005855 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005856 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5857 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005858
5859 def testPreLoadInvalidAlgo(self):
5860 """Test an image with a pre-load header with an invalid algo"""
5861 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005862 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005863
5864 def testPreLoadInvalidKey(self):
5865 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005866 entry_args = {
5867 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5868 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005869 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005870 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5871 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005872
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005873 def _CheckSafeUniqueNames(self, *images):
5874 """Check all entries of given images for unsafe unique names"""
5875 for image in images:
5876 entries = {}
5877 image._CollectEntries(entries, {}, image)
5878 for entry in entries.values():
5879 uniq = entry.GetUniqueName()
5880
5881 # Used as part of a filename, so must not be absolute paths.
5882 self.assertFalse(os.path.isabs(uniq))
5883
5884 def testSafeUniqueNames(self):
5885 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005886 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005887
5888 orig_image = control.images['image']
5889 image_fname = tools.get_output_filename('image.bin')
5890 image = Image.FromFile(image_fname)
5891
5892 self._CheckSafeUniqueNames(orig_image, image)
5893
5894 def testSafeUniqueNamesMulti(self):
5895 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005896 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005897
5898 orig_image = control.images['image']
5899 image_fname = tools.get_output_filename('image.bin')
5900 image = Image.FromFile(image_fname)
5901
5902 self._CheckSafeUniqueNames(orig_image, image)
5903
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005904 def testReplaceCmdWithBintool(self):
5905 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005906 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005907 expected = U_BOOT_DATA + b'aa'
5908 self.assertEqual(expected, data[:len(expected)])
5909
5910 try:
5911 tmpdir, updated_fname = self._SetupImageInTmpdir()
5912 fname = os.path.join(tmpdir, 'update-testing.bin')
5913 tools.write_file(fname, b'zz')
5914 self._DoBinman('replace', '-i', updated_fname,
5915 '_testing', '-f', fname)
5916
5917 data = tools.read_file(updated_fname)
5918 expected = U_BOOT_DATA + b'zz'
5919 self.assertEqual(expected, data[:len(expected)])
5920 finally:
5921 shutil.rmtree(tmpdir)
5922
5923 def testReplaceCmdOtherWithBintool(self):
5924 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005925 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005926 expected = U_BOOT_DATA + b'aa'
5927 self.assertEqual(expected, data[:len(expected)])
5928
5929 try:
5930 tmpdir, updated_fname = self._SetupImageInTmpdir()
5931 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5932 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5933 self._DoBinman('replace', '-i', updated_fname,
5934 'u-boot', '-f', fname)
5935
5936 data = tools.read_file(updated_fname)
5937 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5938 self.assertEqual(expected, data[:len(expected)])
5939 finally:
5940 shutil.rmtree(tmpdir)
5941
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005942 def testReplaceResizeNoRepackSameSize(self):
5943 """Test replacing entries with same-size data without repacking"""
5944 expected = b'x' * len(U_BOOT_DATA)
5945 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5946 self.assertEqual(expected, data)
5947
5948 path, fdtmap = state.GetFdtContents('fdtmap')
5949 self.assertIsNotNone(path)
5950 self.assertEqual(expected_fdtmap, fdtmap)
5951
5952 def testReplaceResizeNoRepackSmallerSize(self):
5953 """Test replacing entries with smaller-size data without repacking"""
5954 new_data = b'x'
5955 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5956 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5957 self.assertEqual(expected, data)
5958
5959 path, fdtmap = state.GetFdtContents('fdtmap')
5960 self.assertIsNotNone(path)
5961 self.assertEqual(expected_fdtmap, fdtmap)
5962
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005963 def testExtractFit(self):
5964 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005965 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005966 image_fname = tools.get_output_filename('image.bin')
5967
5968 fit_data = control.ReadEntry(image_fname, 'fit')
5969 fit = fdt.Fdt.FromData(fit_data)
5970 fit.Scan()
5971
5972 # Check subentry data inside the extracted fit
5973 for node_path, expected in [
5974 ('/images/kernel', U_BOOT_DATA),
5975 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5976 ('/images/scr-1', COMPRESS_DATA),
5977 ]:
5978 node = fit.GetNode(node_path)
5979 data = fit.GetProps(node)['data'].bytes
5980 self.assertEqual(expected, data)
5981
5982 def testExtractFitSubentries(self):
5983 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005984 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005985 image_fname = tools.get_output_filename('image.bin')
5986
5987 for entry_path, expected in [
5988 ('fit/kernel', U_BOOT_DATA),
5989 ('fit/kernel/u-boot', U_BOOT_DATA),
5990 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5991 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5992 ('fit/scr-1', COMPRESS_DATA),
5993 ('fit/scr-1/blob', COMPRESS_DATA),
5994 ]:
5995 data = control.ReadEntry(image_fname, entry_path)
5996 self.assertEqual(expected, data)
5997
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005998 def testReplaceFitSubentryLeafSameSize(self):
5999 """Test replacing a FIT leaf subentry with same-size data"""
6000 new_data = b'x' * len(U_BOOT_DATA)
6001 data, expected_fdtmap, _ = self._RunReplaceCmd(
6002 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006003 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006004 self.assertEqual(new_data, data)
6005
6006 path, fdtmap = state.GetFdtContents('fdtmap')
6007 self.assertIsNotNone(path)
6008 self.assertEqual(expected_fdtmap, fdtmap)
6009
6010 def testReplaceFitSubentryLeafBiggerSize(self):
6011 """Test replacing a FIT leaf subentry with bigger-size data"""
6012 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
6013 data, expected_fdtmap, _ = self._RunReplaceCmd(
6014 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006015 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006016 self.assertEqual(new_data, data)
6017
6018 # Will be repacked, so fdtmap must change
6019 path, fdtmap = state.GetFdtContents('fdtmap')
6020 self.assertIsNotNone(path)
6021 self.assertNotEqual(expected_fdtmap, fdtmap)
6022
6023 def testReplaceFitSubentryLeafSmallerSize(self):
6024 """Test replacing a FIT leaf subentry with smaller-size data"""
6025 new_data = b'x'
6026 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6027 data, expected_fdtmap, _ = self._RunReplaceCmd(
6028 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006029 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006030 self.assertEqual(expected, data)
6031
6032 path, fdtmap = state.GetFdtContents('fdtmap')
6033 self.assertIsNotNone(path)
6034 self.assertEqual(expected_fdtmap, fdtmap)
6035
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006036 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006037 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006038 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006039 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6040 new_data, dts='241_replace_section_simple.dts')
6041 self.assertEqual(new_data, data)
6042
6043 entries = image.GetEntries()
6044 self.assertIn('section', entries)
6045 entry = entries['section']
6046 self.assertEqual(len(new_data), entry.size)
6047
6048 def testReplaceSectionLarger(self):
6049 """Test replacing a simple section with larger data"""
6050 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6051 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6052 new_data, dts='241_replace_section_simple.dts')
6053 self.assertEqual(new_data, data)
6054
6055 entries = image.GetEntries()
6056 self.assertIn('section', entries)
6057 entry = entries['section']
6058 self.assertEqual(len(new_data), entry.size)
6059 fentry = entries['fdtmap']
6060 self.assertEqual(entry.offset + entry.size, fentry.offset)
6061
6062 def testReplaceSectionSmaller(self):
6063 """Test replacing a simple section with smaller data"""
6064 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6065 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6066 new_data, dts='241_replace_section_simple.dts')
6067 self.assertEqual(new_data, data)
6068
6069 # The new size is the same as the old, just with a pad byte at the end
6070 entries = image.GetEntries()
6071 self.assertIn('section', entries)
6072 entry = entries['section']
6073 self.assertEqual(len(new_data), entry.size)
6074
6075 def testReplaceSectionSmallerAllow(self):
6076 """Test failing to replace a simple section with smaller data"""
6077 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6078 try:
6079 state.SetAllowEntryContraction(True)
6080 with self.assertRaises(ValueError) as exc:
6081 self._RunReplaceCmd('section', new_data,
6082 dts='241_replace_section_simple.dts')
6083 finally:
6084 state.SetAllowEntryContraction(False)
6085
6086 # Since we have no information about the position of things within the
6087 # section, we cannot adjust the position of /section-u-boot so it ends
6088 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006089 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006090 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6091 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006092 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006093
Simon Glass8fbca772022-08-13 11:40:48 -06006094 def testMkimageImagename(self):
6095 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006096 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006097 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006098
6099 # Check that the data appears in the file somewhere
6100 self.assertIn(U_BOOT_SPL_DATA, data)
6101
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006102 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006103 name = data[0x20:0x40]
6104
6105 # Build the filename that we expect to be placed in there, by virtue of
6106 # the -n paraameter
6107 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6108
6109 # Check that the image name is set to the temporary filename used
6110 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6111
Simon Glassb1669752022-08-13 11:40:49 -06006112 def testMkimageImage(self):
6113 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006114 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006115 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006116
6117 # Check that the data appears in the file somewhere
6118 self.assertIn(U_BOOT_SPL_DATA, data)
6119
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006120 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006121 name = data[0x20:0x40]
6122
6123 # Build the filename that we expect to be placed in there, by virtue of
6124 # the -n paraameter
6125 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6126
6127 # Check that the image name is set to the temporary filename used
6128 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6129
6130 # Check the corect data is in the imagename file
6131 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6132
6133 def testMkimageImageNoContent(self):
6134 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006135 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006136 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006137 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006138 self.assertIn('Could not complete processing of contents',
6139 str(exc.exception))
6140
6141 def testMkimageImageBad(self):
6142 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006143 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006144 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006145 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006146 self.assertIn('Cannot use both imagename node and data-to-imagename',
6147 str(exc.exception))
6148
Simon Glassbd5cd882022-08-13 11:40:50 -06006149 def testCollectionOther(self):
6150 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006151 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006152 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6153 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6154 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6155 data)
6156
6157 def testMkimageCollection(self):
6158 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006159 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006160 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006161 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6162 self.assertEqual(expect, data[:len(expect)])
6163
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006164 def testCompressDtbPrependInvalid(self):
6165 """Test that invalid header is detected"""
6166 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006167 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006168 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6169 "'u-boot-dtb': 'invalid'", str(e.exception))
6170
6171 def testCompressDtbPrependLength(self):
6172 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006173 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006174 image = control.images['image']
6175 entries = image.GetEntries()
6176 self.assertIn('u-boot-dtb', entries)
6177 u_boot_dtb = entries['u-boot-dtb']
6178 self.assertIn('fdtmap', entries)
6179 fdtmap = entries['fdtmap']
6180
6181 image_fname = tools.get_output_filename('image.bin')
6182 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6183 dtb = fdt.Fdt.FromData(orig)
6184 dtb.Scan()
6185 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6186 expected = {
6187 'u-boot:size': len(U_BOOT_DATA),
6188 'u-boot-dtb:uncomp-size': len(orig),
6189 'u-boot-dtb:size': u_boot_dtb.size,
6190 'fdtmap:size': fdtmap.size,
6191 'size': len(data),
6192 }
6193 self.assertEqual(expected, props)
6194
6195 # Check implementation
6196 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6197 rest = data[len(U_BOOT_DATA):]
6198 comp_data_len = struct.unpack('<I', rest[:4])[0]
6199 comp_data = rest[4:4 + comp_data_len]
6200 orig2 = self._decompress(comp_data)
6201 self.assertEqual(orig, orig2)
6202
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006203 def testInvalidCompress(self):
6204 """Test that invalid compress algorithm is detected"""
6205 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006206 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006207 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6208
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006209 def testCompUtilCompressions(self):
6210 """Test compression algorithms"""
6211 for bintool in self.comp_bintools.values():
6212 self._CheckBintool(bintool)
6213 data = bintool.compress(COMPRESS_DATA)
6214 self.assertNotEqual(COMPRESS_DATA, data)
6215 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006216 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006217
6218 def testCompUtilVersions(self):
6219 """Test tool version of compression algorithms"""
6220 for bintool in self.comp_bintools.values():
6221 self._CheckBintool(bintool)
6222 version = bintool.version()
6223 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6224
6225 def testCompUtilPadding(self):
6226 """Test padding of compression algorithms"""
Jiaxun Yangc6931742025-04-10 06:43:03 -06006227 # Skip zstd and lz4 because they doesn't support padding
6228 for bintool in [v for k,v in self.comp_bintools.items()
6229 if not k in ['zstd', 'lz4']]:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006230 self._CheckBintool(bintool)
6231 data = bintool.compress(COMPRESS_DATA)
6232 self.assertNotEqual(COMPRESS_DATA, data)
6233 data += tools.get_bytes(0, 64)
6234 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006235 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006236
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006237 def testCompressDtbZstd(self):
6238 """Test that zstd compress of device-tree files failed"""
6239 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006240 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006241 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6242 "requires a length header", str(e.exception))
6243
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006244 def testMkimageMultipleDataFiles(self):
6245 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006246 self._SetupSplElf()
6247 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006248 data = self._DoReadFile('252_mkimage_mult_data.dts')
6249 # Size of files are packed in their 4B big-endian format
6250 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6251 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6252 # Size info is always followed by a 4B zero value.
6253 expect += tools.get_bytes(0, 4)
6254 expect += U_BOOT_TPL_DATA
6255 # All but last files are 4B-aligned
6256 align_pad = len(U_BOOT_TPL_DATA) % 4
6257 if align_pad:
6258 expect += tools.get_bytes(0, align_pad)
6259 expect += U_BOOT_SPL_DATA
6260 self.assertEqual(expect, data[-len(expect):])
6261
Marek Vasutf7413f02023-07-18 07:23:58 -06006262 def testMkimageMultipleExpanded(self):
6263 """Test passing multiple files to mkimage in a mkimage entry"""
6264 self._SetupSplElf()
6265 self._SetupTplElf()
6266 entry_args = {
6267 'spl-bss-pad': 'y',
6268 'spl-dtb': 'y',
6269 }
6270 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6271 use_expanded=True, entry_args=entry_args)[0]
6272 pad_len = 10
6273 tpl_expect = U_BOOT_TPL_DATA
6274 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6275 spl_expect += U_BOOT_SPL_DTB_DATA
6276
6277 content = data[0x40:]
6278 lens = struct.unpack('>III', content[:12])
6279
6280 # Size of files are packed in their 4B big-endian format
6281 # Size info is always followed by a 4B zero value.
6282 self.assertEqual(len(tpl_expect), lens[0])
6283 self.assertEqual(len(spl_expect), lens[1])
6284 self.assertEqual(0, lens[2])
6285
6286 rest = content[12:]
6287 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6288
6289 rest = rest[len(tpl_expect):]
6290 align_pad = len(tpl_expect) % 4
6291 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6292 rest = rest[align_pad:]
6293 self.assertEqual(spl_expect, rest)
6294
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006295 def testMkimageMultipleNoContent(self):
6296 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006297 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006298 with self.assertRaises(ValueError) as exc:
6299 self._DoReadFile('253_mkimage_mult_no_content.dts')
6300 self.assertIn('Could not complete processing of contents',
6301 str(exc.exception))
6302
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006303 def testMkimageFilename(self):
6304 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006305 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006306 retcode = self._DoTestFile('254_mkimage_filename.dts')
6307 self.assertEqual(0, retcode)
6308 fname = tools.get_output_filename('mkimage-test.bin')
6309 self.assertTrue(os.path.exists(fname))
6310
Simon Glass56d05412022-02-28 07:16:54 -07006311 def testVpl(self):
6312 """Test that an image with VPL and its device tree can be created"""
6313 # ELF file with a '__bss_size' symbol
6314 self._SetupVplElf()
6315 data = self._DoReadFile('255_u_boot_vpl.dts')
6316 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6317
6318 def testVplNoDtb(self):
6319 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6320 self._SetupVplElf()
6321 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6322 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6323 data[:len(U_BOOT_VPL_NODTB_DATA)])
6324
6325 def testExpandedVpl(self):
6326 """Test that an expanded entry type is selected for TPL when needed"""
6327 self._SetupVplElf()
6328
6329 entry_args = {
6330 'vpl-bss-pad': 'y',
6331 'vpl-dtb': 'y',
6332 }
6333 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6334 entry_args=entry_args)
6335 image = control.images['image']
6336 entries = image.GetEntries()
6337 self.assertEqual(1, len(entries))
6338
6339 # We only have u-boot-vpl, which be expanded
6340 self.assertIn('u-boot-vpl', entries)
6341 entry = entries['u-boot-vpl']
6342 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6343 subent = entry.GetEntries()
6344 self.assertEqual(3, len(subent))
6345 self.assertIn('u-boot-vpl-nodtb', subent)
6346 self.assertIn('u-boot-vpl-bss-pad', subent)
6347 self.assertIn('u-boot-vpl-dtb', subent)
6348
6349 def testVplBssPadMissing(self):
6350 """Test that a missing symbol is detected"""
6351 self._SetupVplElf('u_boot_ucode_ptr')
6352 with self.assertRaises(ValueError) as e:
6353 self._DoReadFile('258_vpl_bss_pad.dts')
6354 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6355 str(e.exception))
6356
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306357 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306358 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306359 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6360 self.assertEqual(0, retcode)
6361 image = control.images['test_image']
6362 fname = tools.get_output_filename('test_image.bin')
6363 sname = tools.get_output_filename('symlink_to_test.bin')
6364 self.assertTrue(os.path.islink(sname))
6365 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006366
Andrew Davis6b463da2023-07-22 00:14:44 +05306367 def testSymlinkOverwrite(self):
6368 """Test that symlinked images can be overwritten"""
6369 testdir = TestFunctional._MakeInputDir('symlinktest')
6370 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6371 # build the same image again in the same directory so that existing symlink is present
6372 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6373 fname = tools.get_output_filename('test_image.bin')
6374 sname = tools.get_output_filename('symlink_to_test.bin')
6375 self.assertTrue(os.path.islink(sname))
6376 self.assertEqual(os.readlink(sname), fname)
6377
Simon Glass37f85de2022-10-20 18:22:47 -06006378 def testSymbolsElf(self):
6379 """Test binman can assign symbols embedded in an ELF file"""
6380 if not elf.ELF_TOOLS:
6381 self.skipTest('Python elftools not available')
6382 self._SetupTplElf('u_boot_binman_syms')
6383 self._SetupVplElf('u_boot_binman_syms')
6384 self._SetupSplElf('u_boot_binman_syms')
6385 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6386 image_fname = tools.get_output_filename('image.bin')
6387
6388 image = control.images['image']
6389 entries = image.GetEntries()
6390
6391 for entry in entries.values():
6392 # No symbols in u-boot and it has faked contents anyway
6393 if entry.name == 'u-boot':
6394 continue
6395 edata = data[entry.image_pos:entry.image_pos + entry.size]
6396 efname = tools.get_output_filename(f'edata-{entry.name}')
6397 tools.write_file(efname, edata)
6398
6399 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6400 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6401 for name, sym in syms.items():
6402 msg = 'test'
6403 val = elf.GetSymbolValue(sym, edata, msg)
6404 entry_m = re_name.match(name)
6405 if entry_m:
6406 ename, prop = entry_m.group(1), entry_m.group(3)
6407 entry, entry_name, prop_name = image.LookupEntry(entries,
6408 name, msg)
Simon Glassd3d3a102025-02-19 08:11:16 -07006409 expect_val = None
Simon Glass37f85de2022-10-20 18:22:47 -06006410 if prop_name == 'offset':
6411 expect_val = entry.offset
6412 elif prop_name == 'image_pos':
6413 expect_val = entry.image_pos
6414 elif prop_name == 'size':
6415 expect_val = entry.size
6416 self.assertEqual(expect_val, val)
6417
6418 def testSymbolsElfBad(self):
6419 """Check error when trying to write symbols without the elftools lib"""
6420 if not elf.ELF_TOOLS:
6421 self.skipTest('Python elftools not available')
6422 self._SetupTplElf('u_boot_binman_syms')
6423 self._SetupVplElf('u_boot_binman_syms')
6424 self._SetupSplElf('u_boot_binman_syms')
6425 try:
6426 elf.ELF_TOOLS = False
6427 with self.assertRaises(ValueError) as exc:
6428 self._DoReadFileDtb('260_symbols_elf.dts')
6429 finally:
6430 elf.ELF_TOOLS = True
6431 self.assertIn(
6432 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6433 'Cannot write symbols to an ELF file without Python elftools',
6434 str(exc.exception))
6435
Simon Glassde244162023-01-07 14:07:08 -07006436 def testSectionFilename(self):
6437 """Check writing of section contents to a file"""
6438 data = self._DoReadFile('261_section_fname.dts')
6439 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6440 tools.get_bytes(ord('!'), 7) +
6441 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6442 self.assertEqual(expected, data)
6443
6444 sect_fname = tools.get_output_filename('outfile.bin')
6445 self.assertTrue(os.path.exists(sect_fname))
6446 sect_data = tools.read_file(sect_fname)
6447 self.assertEqual(U_BOOT_DATA, sect_data)
6448
Simon Glass1e9e61c2023-01-07 14:07:12 -07006449 def testAbsent(self):
6450 """Check handling of absent entries"""
6451 data = self._DoReadFile('262_absent.dts')
6452 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6453
Simon Glassad5cfe12023-01-07 14:07:14 -07006454 def testPackTeeOsOptional(self):
6455 """Test that an image with an optional TEE binary can be created"""
6456 entry_args = {
6457 'tee-os-path': 'tee.elf',
6458 }
6459 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6460 entry_args=entry_args)[0]
6461 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6462
6463 def checkFitTee(self, dts, tee_fname):
6464 """Check that a tee-os entry works and returns data
6465
6466 Args:
6467 dts (str): Device tree filename to use
6468 tee_fname (str): filename containing tee-os
6469
6470 Returns:
6471 bytes: Image contents
6472 """
6473 if not elf.ELF_TOOLS:
6474 self.skipTest('Python elftools not available')
6475 entry_args = {
6476 'of-list': 'test-fdt1 test-fdt2',
6477 'default-dt': 'test-fdt2',
6478 'tee-os-path': tee_fname,
6479 }
6480 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6481 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6482 extra_indirs=[test_subdir])[0]
6483 return data
6484
6485 def testFitTeeOsOptionalFit(self):
6486 """Test an image with a FIT with an optional OP-TEE binary"""
6487 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6488
6489 # There should be only one node, holding the data set up in SetUpClass()
6490 # for tee.bin
6491 dtb = fdt.Fdt.FromData(data)
6492 dtb.Scan()
6493 node = dtb.GetNode('/images/tee-1')
6494 self.assertEqual(TEE_ADDR,
6495 fdt_util.fdt32_to_cpu(node.props['load'].value))
6496 self.assertEqual(TEE_ADDR,
6497 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6498 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6499
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006500 with test_util.capture_sys_output() as (stdout, stderr):
6501 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6502 err = stderr.getvalue()
6503 self.assertRegex(
6504 err,
6505 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6506
Simon Glassad5cfe12023-01-07 14:07:14 -07006507 def testFitTeeOsOptionalFitBad(self):
6508 """Test an image with a FIT with an optional OP-TEE binary"""
6509 with self.assertRaises(ValueError) as exc:
6510 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6511 self.assertIn(
6512 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6513 str(exc.exception))
6514
6515 def testFitTeeOsBad(self):
6516 """Test an OP-TEE binary with wrong formats"""
6517 self.make_tee_bin('tee.bad1', 123)
6518 with self.assertRaises(ValueError) as exc:
6519 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6520 self.assertIn(
6521 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6522 str(exc.exception))
6523
6524 self.make_tee_bin('tee.bad2', 0, b'extra data')
6525 with self.assertRaises(ValueError) as exc:
6526 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6527 self.assertIn(
6528 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6529 str(exc.exception))
6530
Simon Glass63328f12023-01-07 14:07:15 -07006531 def testExtblobOptional(self):
6532 """Test an image with an external blob that is optional"""
6533 with test_util.capture_sys_output() as (stdout, stderr):
6534 data = self._DoReadFile('266_blob_ext_opt.dts')
6535 self.assertEqual(REFCODE_DATA, data)
6536 err = stderr.getvalue()
6537 self.assertRegex(
6538 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006539 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006540
Simon Glass7447a9d2023-01-11 16:10:12 -07006541 def testSectionInner(self):
6542 """Test an inner section with a size"""
6543 data = self._DoReadFile('267_section_inner.dts')
6544 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6545 self.assertEqual(expected, data)
6546
Simon Glassa4948b22023-01-11 16:10:14 -07006547 def testNull(self):
6548 """Test an image with a null entry"""
6549 data = self._DoReadFile('268_null.dts')
6550 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6551
Simon Glassf1ee03b2023-01-11 16:10:16 -07006552 def testOverlap(self):
6553 """Test an image with a overlapping entry"""
6554 data = self._DoReadFile('269_overlap.dts')
6555 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6556
6557 image = control.images['image']
6558 entries = image.GetEntries()
6559
6560 self.assertIn('inset', entries)
6561 inset = entries['inset']
6562 self.assertEqual(1, inset.offset);
6563 self.assertEqual(1, inset.image_pos);
6564 self.assertEqual(2, inset.size);
6565
6566 def testOverlapNull(self):
6567 """Test an image with a null overlap"""
6568 data = self._DoReadFile('270_overlap_null.dts')
6569 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6570
6571 # Check the FMAP
6572 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6573 self.assertEqual(4, fhdr.nareas)
6574 fiter = iter(fentries)
6575
6576 fentry = next(fiter)
6577 self.assertEqual(b'SECTION', fentry.name)
6578 self.assertEqual(0, fentry.offset)
6579 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6580 self.assertEqual(0, fentry.flags)
6581
6582 fentry = next(fiter)
6583 self.assertEqual(b'U_BOOT', fentry.name)
6584 self.assertEqual(0, fentry.offset)
6585 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6586 self.assertEqual(0, fentry.flags)
6587
6588 # Make sure that the NULL entry appears in the FMAP
6589 fentry = next(fiter)
6590 self.assertEqual(b'NULL', fentry.name)
6591 self.assertEqual(1, fentry.offset)
6592 self.assertEqual(2, fentry.size)
6593 self.assertEqual(0, fentry.flags)
6594
6595 fentry = next(fiter)
6596 self.assertEqual(b'FMAP', fentry.name)
6597 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6598
6599 def testOverlapBad(self):
6600 """Test an image with a bad overlapping entry"""
6601 with self.assertRaises(ValueError) as exc:
6602 self._DoReadFile('271_overlap_bad.dts')
6603 self.assertIn(
6604 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6605 str(exc.exception))
6606
6607 def testOverlapNoOffset(self):
6608 """Test an image with a bad overlapping entry"""
6609 with self.assertRaises(ValueError) as exc:
6610 self._DoReadFile('272_overlap_no_size.dts')
6611 self.assertIn(
6612 "Node '/binman/inset': 'fill' entry is missing properties: size",
6613 str(exc.exception))
6614
Simon Glasse0035c92023-01-11 16:10:17 -07006615 def testBlobSymbol(self):
6616 """Test a blob with symbols read from an ELF file"""
6617 elf_fname = self.ElfTestFile('blob_syms')
6618 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6619 TestFunctional._MakeInputFile('blob_syms.bin',
6620 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6621
6622 data = self._DoReadFile('273_blob_symbol.dts')
6623
6624 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6625 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6626 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6627 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6628 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6629
6630 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6631 expected = sym_values
6632 self.assertEqual(expected, data[:len(expected)])
6633
Simon Glass49e9c002023-01-11 16:10:19 -07006634 def testOffsetFromElf(self):
6635 """Test a blob with symbols read from an ELF file"""
6636 elf_fname = self.ElfTestFile('blob_syms')
6637 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6638 TestFunctional._MakeInputFile('blob_syms.bin',
6639 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6640
6641 data = self._DoReadFile('274_offset_from_elf.dts')
6642
6643 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6644 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6645
6646 image = control.images['image']
6647 entries = image.GetEntries()
6648
6649 self.assertIn('inset', entries)
6650 inset = entries['inset']
6651
6652 self.assertEqual(base + 4, inset.offset);
6653 self.assertEqual(base + 4, inset.image_pos);
6654 self.assertEqual(4, inset.size);
6655
6656 self.assertIn('inset2', entries)
6657 inset = entries['inset2']
6658 self.assertEqual(base + 8, inset.offset);
6659 self.assertEqual(base + 8, inset.image_pos);
6660 self.assertEqual(4, inset.size);
6661
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006662 def testFitAlign(self):
6663 """Test an image with an FIT with aligned external data"""
6664 data = self._DoReadFile('275_fit_align.dts')
6665 self.assertEqual(4096, len(data))
6666
6667 dtb = fdt.Fdt.FromData(data)
6668 dtb.Scan()
6669
6670 props = self._GetPropTree(dtb, ['data-position'])
6671 expected = {
6672 'u-boot:data-position': 1024,
6673 'fdt-1:data-position': 2048,
6674 'fdt-2:data-position': 3072,
6675 }
6676 self.assertEqual(expected, props)
6677
Jonas Karlman490f73c2023-01-21 19:02:12 +00006678 def testFitFirmwareLoadables(self):
6679 """Test an image with an FIT that use fit,firmware"""
6680 if not elf.ELF_TOOLS:
6681 self.skipTest('Python elftools not available')
6682 entry_args = {
6683 'of-list': 'test-fdt1',
6684 'default-dt': 'test-fdt1',
6685 'atf-bl31-path': 'bl31.elf',
6686 'tee-os-path': 'missing.bin',
6687 }
6688 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006689 with test_util.capture_sys_output() as (stdout, stderr):
6690 data = self._DoReadFileDtb(
6691 '276_fit_firmware_loadables.dts',
6692 entry_args=entry_args,
6693 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006694
6695 dtb = fdt.Fdt.FromData(data)
6696 dtb.Scan()
6697
6698 node = dtb.GetNode('/configurations/conf-uboot-1')
6699 self.assertEqual('u-boot', node.props['firmware'].value)
6700 self.assertEqual(['atf-1', 'atf-2'],
6701 fdt_util.GetStringList(node, 'loadables'))
6702
6703 node = dtb.GetNode('/configurations/conf-atf-1')
6704 self.assertEqual('atf-1', node.props['firmware'].value)
6705 self.assertEqual(['u-boot', 'atf-2'],
6706 fdt_util.GetStringList(node, 'loadables'))
6707
6708 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6709 self.assertEqual('u-boot', node.props['firmware'].value)
6710 self.assertEqual(['atf-1', 'atf-2'],
6711 fdt_util.GetStringList(node, 'loadables'))
6712
6713 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6714 self.assertEqual('atf-1', node.props['firmware'].value)
6715 self.assertEqual(['u-boot', 'atf-2'],
6716 fdt_util.GetStringList(node, 'loadables'))
6717
6718 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6719 self.assertEqual('atf-1', node.props['firmware'].value)
6720 self.assertEqual(['u-boot', 'atf-2'],
6721 fdt_util.GetStringList(node, 'loadables'))
6722
Simon Glass9a1c7262023-02-22 12:14:49 -07006723 def testTooldir(self):
6724 """Test that we can specify the tooldir"""
6725 with test_util.capture_sys_output() as (stdout, stderr):
6726 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6727 'tool', '-l'))
6728 self.assertEqual('fred', bintool.Bintool.tooldir)
6729
6730 # Check that the toolpath is updated correctly
6731 self.assertEqual(['fred'], tools.tool_search_paths)
6732
6733 # Try with a few toolpaths; the tooldir should be at the end
6734 with test_util.capture_sys_output() as (stdout, stderr):
6735 self.assertEqual(0, self._DoBinman(
6736 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6737 'tool', '-l'))
6738 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6739
Simon Glass49b77e82023-03-02 17:02:44 -07006740 def testReplaceSectionEntry(self):
6741 """Test replacing an entry in a section"""
6742 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6743 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6744 expect_data, dts='241_replace_section_simple.dts')
6745 self.assertEqual(expect_data, entry_data)
6746
6747 entries = image.GetEntries()
6748 self.assertIn('section', entries)
6749 section = entries['section']
6750
6751 sect_entries = section.GetEntries()
6752 self.assertIn('blob', sect_entries)
6753 entry = sect_entries['blob']
6754 self.assertEqual(len(expect_data), entry.size)
6755
6756 fname = tools.get_output_filename('image-updated.bin')
6757 data = tools.read_file(fname)
6758
6759 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6760 self.assertEqual(expect_data, new_blob_data)
6761
6762 self.assertEqual(U_BOOT_DATA,
6763 data[entry.image_pos + len(expect_data):]
6764 [:len(U_BOOT_DATA)])
6765
6766 def testReplaceSectionDeep(self):
6767 """Test replacing an entry in two levels of sections"""
6768 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6769 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6770 'section/section/blob', expect_data,
6771 dts='278_replace_section_deep.dts')
6772 self.assertEqual(expect_data, entry_data)
6773
6774 entries = image.GetEntries()
6775 self.assertIn('section', entries)
6776 section = entries['section']
6777
6778 subentries = section.GetEntries()
6779 self.assertIn('section', subentries)
6780 section = subentries['section']
6781
6782 sect_entries = section.GetEntries()
6783 self.assertIn('blob', sect_entries)
6784 entry = sect_entries['blob']
6785 self.assertEqual(len(expect_data), entry.size)
6786
6787 fname = tools.get_output_filename('image-updated.bin')
6788 data = tools.read_file(fname)
6789
6790 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6791 self.assertEqual(expect_data, new_blob_data)
6792
6793 self.assertEqual(U_BOOT_DATA,
6794 data[entry.image_pos + len(expect_data):]
6795 [:len(U_BOOT_DATA)])
6796
6797 def testReplaceFitSibling(self):
6798 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006799 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006800 fname = TestFunctional._MakeInputFile('once', b'available once')
6801 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6802 os.remove(fname)
6803
6804 try:
6805 tmpdir, updated_fname = self._SetupImageInTmpdir()
6806
6807 fname = os.path.join(tmpdir, 'update-blob')
6808 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6809 tools.write_file(fname, expected)
6810
6811 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6812 data = tools.read_file(updated_fname)
6813 start = len(U_BOOT_DTB_DATA)
6814 self.assertEqual(expected, data[start:start + len(expected)])
6815 map_fname = os.path.join(tmpdir, 'image-updated.map')
6816 self.assertFalse(os.path.exists(map_fname))
6817 finally:
6818 shutil.rmtree(tmpdir)
6819
Simon Glassc3fe97f2023-03-02 17:02:45 -07006820 def testX509Cert(self):
6821 """Test creating an X509 certificate"""
6822 keyfile = self.TestFile('key.key')
6823 entry_args = {
6824 'keyfile': keyfile,
6825 }
6826 data = self._DoReadFileDtb('279_x509_cert.dts',
6827 entry_args=entry_args)[0]
6828 cert = data[:-4]
6829 self.assertEqual(U_BOOT_DATA, data[-4:])
6830
6831 # TODO: verify the signature
6832
6833 def testX509CertMissing(self):
6834 """Test that binman still produces an image if openssl is missing"""
6835 keyfile = self.TestFile('key.key')
6836 entry_args = {
6837 'keyfile': 'keyfile',
6838 }
6839 with test_util.capture_sys_output() as (_, stderr):
6840 self._DoTestFile('279_x509_cert.dts',
6841 force_missing_bintools='openssl',
6842 entry_args=entry_args)
6843 err = stderr.getvalue()
6844 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6845
Jonas Karlman35305492023-02-25 19:01:33 +00006846 def testPackRockchipTpl(self):
6847 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006848 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006849 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6850
Jonas Karlman1016ec72023-02-25 19:01:35 +00006851 def testMkimageMissingBlobMultiple(self):
6852 """Test missing blob with mkimage entry and multiple-data-files"""
6853 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006854 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006855 err = stderr.getvalue()
6856 self.assertIn("is missing external blobs and is non-functional", err)
6857
6858 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006859 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006860 self.assertIn("not found in input path", str(e.exception))
6861
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006862 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6863 """Prepare sign environment
6864
6865 Create private and public keys, add pubkey into dtb.
6866
6867 Returns:
6868 Tuple:
6869 FIT container
6870 Image name
6871 Private key
6872 DTB
6873 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006874 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006875 data = self._DoReadFileRealDtb(dts)
6876 updated_fname = tools.get_output_filename('image-updated.bin')
6877 tools.write_file(updated_fname, data)
6878 dtb = tools.get_output_filename('source.dtb')
6879 private_key = tools.get_output_filename('test_key.key')
6880 public_key = tools.get_output_filename('test_key.crt')
6881 fit = tools.get_output_filename('fit.fit')
6882 key_dir = tools.get_output_dir()
6883
6884 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6885 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6886 private_key, '-out', public_key)
6887 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6888 '-n', 'test_key', '-r', 'conf', dtb)
6889
6890 return fit, updated_fname, private_key, dtb
6891
6892 def testSignSimple(self):
6893 """Test that a FIT container can be signed in image"""
6894 is_signed = False
6895 fit, fname, private_key, dtb = self._PrepareSignEnv()
6896
6897 # do sign with private key
6898 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6899 ['fit'])
6900 is_signed = self._CheckSign(fit, dtb)
6901
6902 self.assertEqual(is_signed, True)
6903
6904 def testSignExactFIT(self):
6905 """Test that a FIT container can be signed and replaced in image"""
6906 is_signed = False
6907 fit, fname, private_key, dtb = self._PrepareSignEnv()
6908
6909 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6910 args = []
6911 if self.toolpath:
6912 for path in self.toolpath:
6913 args += ['--toolpath', path]
6914
6915 # do sign with private key
6916 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6917 'sha256,rsa4096', '-f', fit, 'fit')
6918 is_signed = self._CheckSign(fit, dtb)
6919
6920 self.assertEqual(is_signed, True)
6921
6922 def testSignNonFit(self):
6923 """Test a non-FIT entry cannot be signed"""
6924 is_signed = False
6925 fit, fname, private_key, _ = self._PrepareSignEnv(
6926 '281_sign_non_fit.dts')
6927
6928 # do sign with private key
6929 with self.assertRaises(ValueError) as e:
6930 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6931 'sha256,rsa4096', '-f', fit, 'u-boot')
6932 self.assertIn(
6933 "Node '/u-boot': Updating signatures is not supported with this entry type",
6934 str(e.exception))
6935
6936 def testSignMissingMkimage(self):
6937 """Test that FIT signing handles a missing mkimage tool"""
6938 fit, fname, private_key, _ = self._PrepareSignEnv()
6939
6940 # try to sign with a missing mkimage tool
6941 bintool.Bintool.set_missing_list(['mkimage'])
6942 with self.assertRaises(ValueError) as e:
6943 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6944 ['fit'])
6945 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6946
Simon Glass4abf7842023-07-18 07:23:54 -06006947 def testSymbolNoWrite(self):
6948 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006949 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006950 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6951 no_write_symbols=True)
6952
6953 def testSymbolNoWriteExpanded(self):
6954 """Test disabling of symbol writing in expanded entries"""
6955 entry_args = {
6956 'spl-dtb': '1',
6957 }
6958 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6959 U_BOOT_SPL_DTB_DATA, 0x38,
6960 entry_args=entry_args, use_expanded=True,
6961 no_write_symbols=True)
6962
Marek Vasutf7413f02023-07-18 07:23:58 -06006963 def testMkimageSpecial(self):
6964 """Test mkimage ignores special hash-1 node"""
6965 data = self._DoReadFile('283_mkimage_special.dts')
6966
6967 # Just check that the data appears in the file somewhere
6968 self.assertIn(U_BOOT_DATA, data)
6969
Simon Glass2d94c422023-07-18 07:23:59 -06006970 def testFitFdtList(self):
6971 """Test an image with an FIT with the fit,fdt-list-val option"""
6972 entry_args = {
6973 'default-dt': 'test-fdt2',
6974 }
6975 data = self._DoReadFileDtb(
6976 '284_fit_fdt_list.dts',
6977 entry_args=entry_args,
6978 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6979 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6980 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6981
Simon Glass83b8bfe2023-07-18 07:24:01 -06006982 def testSplEmptyBss(self):
6983 """Test an expanded SPL with a zero-size BSS"""
6984 # ELF file with a '__bss_size' symbol
6985 self._SetupSplElf(src_fname='bss_data_zero')
6986
6987 entry_args = {
6988 'spl-bss-pad': 'y',
6989 'spl-dtb': 'y',
6990 }
6991 data = self._DoReadFileDtb('285_spl_expand.dts',
6992 use_expanded=True, entry_args=entry_args)[0]
6993
Simon Glassfc792842023-07-18 07:24:04 -06006994 def testTemplate(self):
6995 """Test using a template"""
6996 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6997 data = self._DoReadFile('286_template.dts')
6998 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6999 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7000 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
7001
Simon Glass09490b02023-07-22 21:43:52 -06007002 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
7003 self.assertTrue(os.path.exists(dtb_fname1))
7004 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
7005 dtb.Scan()
7006 node1 = dtb.GetNode('/binman/template')
7007 self.assertTrue(node1)
7008 vga = dtb.GetNode('/binman/first/intel-vga')
7009 self.assertTrue(vga)
7010
Simon Glass54825e12023-07-22 21:43:56 -06007011 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
7012 self.assertTrue(os.path.exists(dtb_fname2))
7013 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
7014 dtb2.Scan()
7015 node2 = dtb2.GetNode('/binman/template')
7016 self.assertFalse(node2)
7017
Simon Glass9909c112023-07-18 07:24:05 -06007018 def testTemplateBlobMulti(self):
7019 """Test using a template with 'multiple-images' enabled"""
7020 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7021 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
7022 retcode = self._DoTestFile('287_template_multi.dts')
7023
7024 self.assertEqual(0, retcode)
7025 image = control.images['image']
7026 image_fname = tools.get_output_filename('my-image.bin')
7027 data = tools.read_file(image_fname)
7028 self.assertEqual(b'blob@@@@other', data)
7029
Simon Glass5dc511b2023-07-18 07:24:06 -06007030 def testTemplateFit(self):
7031 """Test using a template in a FIT"""
7032 fit_data = self._DoReadFile('288_template_fit.dts')
7033 fname = os.path.join(self._indir, 'fit_data.fit')
7034 tools.write_file(fname, fit_data)
7035 out = tools.run('dumpimage', '-l', fname)
7036
Simon Glassaa6e0552023-07-18 07:24:07 -06007037 def testTemplateSection(self):
7038 """Test using a template in a section (not at top level)"""
7039 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7040 data = self._DoReadFile('289_template_section.dts')
7041 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7042 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7043 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7044
Simon Glassf53a7bc2023-07-18 07:24:08 -06007045 def testMkimageSymbols(self):
7046 """Test using mkimage to build an image with symbols in it"""
7047 self._SetupSplElf('u_boot_binman_syms')
7048 data = self._DoReadFile('290_mkimage_sym.dts')
7049
7050 image = control.images['image']
7051 entries = image.GetEntries()
7052 self.assertIn('u-boot', entries)
7053 u_boot = entries['u-boot']
7054
7055 mkim = entries['mkimage']
7056 mkim_entries = mkim.GetEntries()
7057 self.assertIn('u-boot-spl', mkim_entries)
7058 spl = mkim_entries['u-boot-spl']
7059 self.assertIn('u-boot-spl2', mkim_entries)
7060 spl2 = mkim_entries['u-boot-spl2']
7061
7062 # skip the mkimage header and the area sizes
7063 mk_data = data[mkim.offset + 0x40:]
7064 size, term = struct.unpack('>LL', mk_data[:8])
7065
7066 # There should be only one image, so check that the zero terminator is
7067 # present
7068 self.assertEqual(0, term)
7069
7070 content = mk_data[8:8 + size]
7071
7072 # The image should contain the symbols from u_boot_binman_syms.c
7073 # Note that image_pos is adjusted by the base address of the image,
7074 # which is 0x10 in our test image
7075 spl_data = content[:0x18]
7076 content = content[0x1b:]
7077
7078 # After the header is a table of offsets for each image. There should
7079 # only be one image, then a 0 terminator, so figure out the real start
7080 # of the image data
7081 base = 0x40 + 8
7082
7083 # Check symbols in both u-boot-spl and u-boot-spl2
7084 for i in range(2):
7085 vals = struct.unpack('<LLQLL', spl_data)
7086
7087 # The image should contain the symbols from u_boot_binman_syms.c
7088 # Note that image_pos is adjusted by the base address of the image,
7089 # which is 0x10 in our 'u_boot_binman_syms' test image
7090 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7091 self.assertEqual(base, vals[1])
7092 self.assertEqual(spl2.offset, vals[2])
7093 # figure out the internal positions of its components
7094 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7095
7096 # Check that spl and spl2 are actually at the indicated positions
7097 self.assertEqual(
7098 elf.BINMAN_SYM_MAGIC_VALUE,
7099 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7100 self.assertEqual(
7101 elf.BINMAN_SYM_MAGIC_VALUE,
7102 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7103
7104 self.assertEqual(len(U_BOOT_DATA), vals[4])
7105
7106 # Move to next
7107 spl_data = content[:0x18]
7108
Simon Glass86b3e472023-07-22 21:43:57 -06007109 def testTemplatePhandle(self):
7110 """Test using a template in a node containing a phandle"""
7111 entry_args = {
7112 'atf-bl31-path': 'bl31.elf',
7113 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007114 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007115 entry_args=entry_args)
7116 fname = tools.get_output_filename('image.bin')
7117 out = tools.run('dumpimage', '-l', fname)
7118
7119 # We should see the FIT description and one for each of the two images
7120 lines = out.splitlines()
7121 descs = [line.split()[-1] for line in lines if 'escription' in line]
7122 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7123
7124 def testTemplatePhandleDup(self):
7125 """Test using a template in a node containing a phandle"""
7126 entry_args = {
7127 'atf-bl31-path': 'bl31.elf',
7128 }
7129 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007130 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007131 entry_args=entry_args)
7132 self.assertIn(
7133 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7134 str(e.exception))
7135
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307136 def testTIBoardConfig(self):
7137 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007138 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307139 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7140
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307141 def testTIBoardConfigLint(self):
7142 """Test that an incorrectly linted config file would generate error"""
7143 with self.assertRaises(ValueError) as e:
7144 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7145 self.assertIn("Yamllint error", str(e.exception))
7146
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307147 def testTIBoardConfigCombined(self):
7148 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007149 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307150 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7151 self.assertGreater(data, configlen_noheader)
7152
7153 def testTIBoardConfigNoDataType(self):
7154 """Test that error is thrown when data type is not supported"""
7155 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007156 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307157 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007158
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307159 def testPackTiSecure(self):
7160 """Test that an image with a TI secured binary can be created"""
7161 keyfile = self.TestFile('key.key')
7162 entry_args = {
7163 'keyfile': keyfile,
7164 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007165 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307166 entry_args=entry_args)[0]
7167 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7168
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307169 def testPackTiSecureFirewall(self):
7170 """Test that an image with a TI secured binary can be created"""
7171 keyfile = self.TestFile('key.key')
7172 entry_args = {
7173 'keyfile': keyfile,
7174 }
7175 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7176 entry_args=entry_args)[0]
7177 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7178 entry_args=entry_args)[0]
7179 self.assertGreater(len(data_firewall),len(data_no_firewall))
7180
7181 def testPackTiSecureFirewallMissingProperty(self):
7182 """Test that an image with a TI secured binary can be created"""
7183 keyfile = self.TestFile('key.key')
7184 entry_args = {
7185 'keyfile': keyfile,
7186 }
7187 with self.assertRaises(ValueError) as e:
7188 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7189 entry_args=entry_args)[0]
7190 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7191
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307192 def testPackTiSecureMissingTool(self):
7193 """Test that an image with a TI secured binary (non-functional) can be created
7194 when openssl is missing"""
7195 keyfile = self.TestFile('key.key')
7196 entry_args = {
7197 'keyfile': keyfile,
7198 }
7199 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007200 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307201 force_missing_bintools='openssl',
7202 entry_args=entry_args)
7203 err = stderr.getvalue()
7204 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7205
7206 def testPackTiSecureROM(self):
7207 """Test that a ROM image with a TI secured binary can be created"""
7208 keyfile = self.TestFile('key.key')
7209 entry_args = {
7210 'keyfile': keyfile,
7211 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007212 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307213 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007214 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307215 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007216 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307217 entry_args=entry_args)[0]
7218 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7219 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7220 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7221
7222 def testPackTiSecureROMCombined(self):
7223 """Test that a ROM image with a TI secured binary can be created"""
7224 keyfile = self.TestFile('key.key')
7225 entry_args = {
7226 'keyfile': keyfile,
7227 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007228 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307229 entry_args=entry_args)[0]
7230 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7231
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007232 def testEncryptedNoAlgo(self):
7233 """Test encrypted node with missing required properties"""
7234 with self.assertRaises(ValueError) as e:
7235 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7236 self.assertIn(
7237 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7238 str(e.exception))
7239
7240 def testEncryptedInvalidIvfile(self):
7241 """Test encrypted node with invalid iv file"""
7242 with self.assertRaises(ValueError) as e:
7243 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7244 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7245 str(e.exception))
7246
7247 def testEncryptedMissingKey(self):
7248 """Test encrypted node with missing key properties"""
7249 with self.assertRaises(ValueError) as e:
7250 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7251 self.assertIn(
7252 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7253 str(e.exception))
7254
7255 def testEncryptedKeySource(self):
7256 """Test encrypted node with key-source property"""
7257 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7258
7259 dtb = fdt.Fdt.FromData(data)
7260 dtb.Scan()
7261
7262 node = dtb.GetNode('/images/u-boot/cipher')
7263 self.assertEqual('algo-name', node.props['algo'].value)
7264 self.assertEqual('key-source-value', node.props['key-source'].value)
7265 self.assertEqual(ENCRYPTED_IV_DATA,
7266 tools.to_bytes(''.join(node.props['iv'].value)))
7267 self.assertNotIn('key', node.props)
7268
7269 def testEncryptedKeyFile(self):
7270 """Test encrypted node with key-filename property"""
7271 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7272
7273 dtb = fdt.Fdt.FromData(data)
7274 dtb.Scan()
7275
7276 node = dtb.GetNode('/images/u-boot/cipher')
7277 self.assertEqual('algo-name', node.props['algo'].value)
7278 self.assertEqual(ENCRYPTED_IV_DATA,
7279 tools.to_bytes(''.join(node.props['iv'].value)))
7280 self.assertEqual(ENCRYPTED_KEY_DATA,
7281 tools.to_bytes(''.join(node.props['key'].value)))
7282 self.assertNotIn('key-source', node.props)
7283
Lukas Funkee901faf2023-07-18 13:53:13 +02007284
7285 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007286 """Test u_boot_spl_pubkey_dtb etype"""
7287 data = tools.read_file(self.TestFile("key.pem"))
7288 self._MakeInputFile("key.crt", data)
7289 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7290 image = control.images['image']
7291 entries = image.GetEntries()
7292 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7293 dtb_data = dtb_entry.GetData()
7294 dtb = fdt.Fdt.FromData(dtb_data)
7295 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007296
Simon Glass4b861272024-07-20 11:49:41 +01007297 signature_node = dtb.GetNode('/signature')
7298 self.assertIsNotNone(signature_node)
7299 key_node = signature_node.FindNode("key-key")
7300 self.assertIsNotNone(key_node)
7301 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7302 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7303 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007304
Lukas Funke712e1062023-08-03 17:22:14 +02007305 def testXilinxBootgenSigning(self):
7306 """Test xilinx-bootgen etype"""
7307 bootgen = bintool.Bintool.create('bootgen')
7308 self._CheckBintool(bootgen)
7309 data = tools.read_file(self.TestFile("key.key"))
7310 self._MakeInputFile("psk.pem", data)
7311 self._MakeInputFile("ssk.pem", data)
7312 self._SetupPmuFwlElf()
7313 self._SetupSplElf()
7314 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7315 image_fname = tools.get_output_filename('image.bin')
7316
7317 # Read partition header table and check if authentication is enabled
7318 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7319 "-read", image_fname, "pht").splitlines()
7320 attributes = {"authentication": None,
7321 "core": None,
7322 "encryption": None}
7323
7324 for l in bootgen_out:
7325 for a in attributes.keys():
7326 if a in l:
7327 m = re.match(fr".*{a} \[([^]]+)\]", l)
7328 attributes[a] = m.group(1)
7329
7330 self.assertTrue(attributes['authentication'] == "rsa")
7331 self.assertTrue(attributes['core'] == "a53-0")
7332 self.assertTrue(attributes['encryption'] == "no")
7333
7334 def testXilinxBootgenSigningEncryption(self):
7335 """Test xilinx-bootgen etype"""
7336 bootgen = bintool.Bintool.create('bootgen')
7337 self._CheckBintool(bootgen)
7338 data = tools.read_file(self.TestFile("key.key"))
7339 self._MakeInputFile("psk.pem", data)
7340 self._MakeInputFile("ssk.pem", data)
7341 self._SetupPmuFwlElf()
7342 self._SetupSplElf()
7343 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7344 image_fname = tools.get_output_filename('image.bin')
7345
7346 # Read boot header in order to verify encryption source and
7347 # encryption parameter
7348 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7349 "-read", image_fname, "bh").splitlines()
7350 attributes = {"auth_only":
7351 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7352 "encryption_keystore":
7353 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7354 "value": None},
7355 }
7356
7357 for l in bootgen_out:
7358 for a in attributes.keys():
7359 if a in l:
7360 m = re.match(attributes[a]['re'], l)
7361 attributes[a] = m.group(1)
7362
7363 # Check if fsbl-attribute is set correctly
7364 self.assertTrue(attributes['auth_only'] == "true")
7365 # Check if key is stored in efuse
7366 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7367
7368 def testXilinxBootgenMissing(self):
7369 """Test that binman still produces an image if bootgen is missing"""
7370 data = tools.read_file(self.TestFile("key.key"))
7371 self._MakeInputFile("psk.pem", data)
7372 self._MakeInputFile("ssk.pem", data)
7373 self._SetupPmuFwlElf()
7374 self._SetupSplElf()
7375 with test_util.capture_sys_output() as (_, stderr):
7376 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7377 force_missing_bintools='bootgen')
7378 err = stderr.getvalue()
7379 self.assertRegex(err,
7380 "Image 'image'.*missing bintools.*: bootgen")
7381
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307382 def _GetCapsuleHeaders(self, data):
7383 """Get the capsule header contents
7384
7385 Args:
7386 data: Capsule file contents
7387
7388 Returns:
7389 Dict:
7390 key: Capsule Header name (str)
7391 value: Header field value (str)
7392 """
7393 capsule_file = os.path.join(self._indir, 'test.capsule')
7394 tools.write_file(capsule_file, data)
7395
7396 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7397 lines = out.splitlines()
7398
7399 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7400 vals = {}
7401 for line in lines:
7402 mat = re_line.match(line)
7403 if mat:
7404 vals[mat.group(1)] = mat.group(2)
7405
7406 return vals
7407
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307408 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7409 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307410 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7411 fmp_size = "00000010"
7412 fmp_fw_version = "00000002"
7413 capsule_image_index = "00000001"
7414 oemflag = "00018000"
7415 auth_hdr_revision = "00000200"
7416 auth_hdr_cert_type = "00000EF1"
7417
7418 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307419
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307420 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307421
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307422 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307423
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307424 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7425 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7426 self.assertEqual(capsule_image_index,
7427 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307428
7429 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307430 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7431
7432 if signed_capsule:
7433 self.assertEqual(auth_hdr_revision,
7434 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7435 self.assertEqual(auth_hdr_cert_type,
7436 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7437 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7438 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7439
7440 if version_check:
7441 self.assertEqual(fmp_signature,
7442 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7443 self.assertEqual(fmp_size,
7444 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7445 self.assertEqual(fmp_fw_version,
7446 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7447
7448 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307449
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307450 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7451 if accept_capsule:
7452 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7453 else:
7454 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7455
7456 hdr = self._GetCapsuleHeaders(data)
7457
7458 self.assertEqual(capsule_hdr_guid.upper(),
7459 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7460
7461 if accept_capsule:
7462 capsule_size = "0000002C"
7463 else:
7464 capsule_size = "0000001C"
7465 self.assertEqual(capsule_size,
7466 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7467
7468 if accept_capsule:
7469 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7470
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307471 def testCapsuleGen(self):
7472 """Test generation of EFI capsule"""
7473 data = self._DoReadFile('311_capsule.dts')
7474
7475 self._CheckCapsule(data)
7476
7477 def testSignedCapsuleGen(self):
7478 """Test generation of EFI capsule"""
7479 data = tools.read_file(self.TestFile("key.key"))
7480 self._MakeInputFile("key.key", data)
7481 data = tools.read_file(self.TestFile("key.pem"))
7482 self._MakeInputFile("key.crt", data)
7483
7484 data = self._DoReadFile('312_capsule_signed.dts')
7485
7486 self._CheckCapsule(data, signed_capsule=True)
7487
7488 def testCapsuleGenVersionSupport(self):
7489 """Test generation of EFI capsule with version support"""
7490 data = self._DoReadFile('313_capsule_version.dts')
7491
7492 self._CheckCapsule(data, version_check=True)
7493
7494 def testCapsuleGenSignedVer(self):
7495 """Test generation of signed EFI capsule with version information"""
7496 data = tools.read_file(self.TestFile("key.key"))
7497 self._MakeInputFile("key.key", data)
7498 data = tools.read_file(self.TestFile("key.pem"))
7499 self._MakeInputFile("key.crt", data)
7500
7501 data = self._DoReadFile('314_capsule_signed_ver.dts')
7502
7503 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7504
7505 def testCapsuleGenCapOemFlags(self):
7506 """Test generation of EFI capsule with OEM Flags set"""
7507 data = self._DoReadFile('315_capsule_oemflags.dts')
7508
7509 self._CheckCapsule(data, capoemflags=True)
7510
7511 def testCapsuleGenKeyMissing(self):
7512 """Test that binman errors out on missing key"""
7513 with self.assertRaises(ValueError) as e:
7514 self._DoReadFile('316_capsule_missing_key.dts')
7515
7516 self.assertIn("Both private key and public key certificate need to be provided",
7517 str(e.exception))
7518
7519 def testCapsuleGenIndexMissing(self):
7520 """Test that binman errors out on missing image index"""
7521 with self.assertRaises(ValueError) as e:
7522 self._DoReadFile('317_capsule_missing_index.dts')
7523
7524 self.assertIn("entry is missing properties: image-index",
7525 str(e.exception))
7526
7527 def testCapsuleGenGuidMissing(self):
7528 """Test that binman errors out on missing image GUID"""
7529 with self.assertRaises(ValueError) as e:
7530 self._DoReadFile('318_capsule_missing_guid.dts')
7531
7532 self.assertIn("entry is missing properties: image-guid",
7533 str(e.exception))
7534
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307535 def testCapsuleGenAcceptCapsule(self):
7536 """Test generationg of accept EFI capsule"""
7537 data = self._DoReadFile('319_capsule_accept.dts')
7538
7539 self._CheckEmptyCapsule(data, accept_capsule=True)
7540
7541 def testCapsuleGenRevertCapsule(self):
7542 """Test generationg of revert EFI capsule"""
7543 data = self._DoReadFile('320_capsule_revert.dts')
7544
7545 self._CheckEmptyCapsule(data)
7546
7547 def testCapsuleGenAcceptGuidMissing(self):
7548 """Test that binman errors out on missing image GUID for accept capsule"""
7549 with self.assertRaises(ValueError) as e:
7550 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7551
7552 self.assertIn("Image GUID needed for generating accept capsule",
7553 str(e.exception))
7554
7555 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7556 """Test that capsule-type is specified"""
7557 with self.assertRaises(ValueError) as e:
7558 self._DoReadFile('322_empty_capsule_type_missing.dts')
7559
7560 self.assertIn("entry is missing properties: capsule-type",
7561 str(e.exception))
7562
7563 def testCapsuleGenAcceptOrRevertMissing(self):
7564 """Test that both accept and revert capsule are not specified"""
7565 with self.assertRaises(ValueError) as e:
7566 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7567
Simon Glassa360b8f2024-06-23 11:55:06 -06007568 def test_assume_size(self):
7569 """Test handling of the assume-size property for external blob"""
7570 with self.assertRaises(ValueError) as e:
7571 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7572 allow_fake_blobs=True)
7573 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7574 str(e.exception))
7575
7576 def test_assume_size_ok(self):
7577 """Test handling of the assume-size where it fits OK"""
7578 with test_util.capture_sys_output() as (stdout, stderr):
7579 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7580 allow_fake_blobs=True)
7581 err = stderr.getvalue()
7582 self.assertRegex(
7583 err,
7584 "Image '.*' has faked external blobs and is non-functional: .*")
7585
7586 def test_assume_size_no_fake(self):
7587 """Test handling of the assume-size where it fits OK"""
7588 with test_util.capture_sys_output() as (stdout, stderr):
7589 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7590 err = stderr.getvalue()
7591 self.assertRegex(
7592 err,
7593 "Image '.*' is missing external blobs and is non-functional: .*")
7594
Simon Glass5f7aadf2024-07-20 11:49:47 +01007595 def SetupAlternateDts(self):
7596 """Compile the .dts test files for alternative-fdt
7597
7598 Returns:
7599 tuple:
7600 str: Test directory created
7601 list of str: '.bin' files which we expect Binman to create
7602 """
7603 testdir = TestFunctional._MakeInputDir('dtb')
7604 dtb_list = []
7605 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7606 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7607 base = os.path.splitext(os.path.basename(fname))[0]
7608 dtb_list.append(base + '.bin')
7609 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7610
7611 return testdir, dtb_list
7612
Simon Glassf3598922024-07-20 11:49:45 +01007613 def CheckAlternates(self, dts, phase, xpl_data):
7614 """Run the test for the alterative-fdt etype
7615
7616 Args:
7617 dts (str): Devicetree file to process
7618 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7619 xpl_data (bytes): Expected data for the phase's binary
7620
7621 Returns:
7622 dict of .dtb files produced
7623 key: str filename
7624 value: Fdt object
7625 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007626 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007627
7628 entry_args = {
7629 f'{phase}-dtb': '1',
7630 f'{phase}-bss-pad': 'y',
7631 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7632 }
7633 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7634 use_expanded=True, entry_args=entry_args)[0]
7635 self.assertEqual(xpl_data, data[:len(xpl_data)])
7636 rest = data[len(xpl_data):]
7637 pad_len = 10
7638 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7639
7640 # Check the dtb is using the test file
7641 dtb_data = rest[pad_len:]
7642 dtb = fdt.Fdt.FromData(dtb_data)
7643 dtb.Scan()
7644 fdt_size = dtb.GetFdtObj().totalsize()
7645 self.assertEqual('model-not-set',
7646 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7647
7648 pad_len = 10
7649
7650 # Check the other output files
7651 dtbs = {}
7652 for fname in dtb_list:
7653 pathname = tools.get_output_filename(fname)
7654 self.assertTrue(os.path.exists(pathname))
7655
7656 data = tools.read_file(pathname)
7657 self.assertEqual(xpl_data, data[:len(xpl_data)])
7658 rest = data[len(xpl_data):]
7659
7660 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7661 rest = rest[pad_len:]
7662
7663 dtb = fdt.Fdt.FromData(rest)
7664 dtb.Scan()
7665 dtbs[fname] = dtb
7666
7667 expected = 'one' if '1' in fname else 'two'
7668 self.assertEqual(f'u-boot,model-{expected}',
7669 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7670
7671 # Make sure the FDT is the same size as the 'main' one
7672 rest = rest[fdt_size:]
7673
7674 self.assertEqual(b'', rest)
7675 return dtbs
7676
7677 def testAlternatesFdt(self):
7678 """Test handling of alternates-fdt etype"""
7679 self._SetupTplElf()
7680 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7681 U_BOOT_TPL_NODTB_DATA)
7682 for dtb in dtbs.values():
7683 # Check for the node with the tag
7684 node = dtb.GetNode('/node')
7685 self.assertIsNotNone(node)
7686 self.assertEqual(5, len(node.props.keys()))
7687
7688 # Make sure the other node is still there
7689 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7690
7691 def testAlternatesFdtgrep(self):
7692 """Test handling of alternates-fdt etype using fdtgrep"""
7693 self._SetupTplElf()
7694 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7695 U_BOOT_TPL_NODTB_DATA)
7696 for dtb in dtbs.values():
7697 # Check for the node with the tag
7698 node = dtb.GetNode('/node')
7699 self.assertIsNotNone(node)
7700 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7701 node.props.keys())
7702
7703 # Make sure the other node is gone
7704 self.assertIsNone(dtb.GetNode('/node/other-node'))
7705
7706 def testAlternatesFdtgrepVpl(self):
7707 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7708 self._SetupVplElf()
7709 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7710 U_BOOT_VPL_NODTB_DATA)
7711
7712 def testAlternatesFdtgrepSpl(self):
7713 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7714 self._SetupSplElf()
7715 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7716 U_BOOT_SPL_NODTB_DATA)
7717
7718 def testAlternatesFdtgrepInval(self):
7719 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7720 self._SetupSplElf()
7721 with self.assertRaises(ValueError) as e:
7722 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7723 U_BOOT_SPL_NODTB_DATA)
7724 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7725 str(e.exception))
7726
Simon Glasscd2783e2024-07-20 11:49:46 +01007727 def testFitFdtListDir(self):
7728 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007729 old_dir = os.getcwd()
7730 try:
7731 os.chdir(self._indir)
7732 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7733 finally:
7734 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007735
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007736 def testFitFdtListDirDefault(self):
7737 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7738 old_dir = os.getcwd()
7739 try:
7740 os.chdir(self._indir)
7741 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7742 default_dt='rockchip/test-fdt2')
7743 finally:
7744 os.chdir(old_dir)
7745
Simon Glass5f7aadf2024-07-20 11:49:47 +01007746 def testFitFdtCompat(self):
7747 """Test an image with an FIT with compatible in the config nodes"""
7748 entry_args = {
7749 'of-list': 'model1 model2',
7750 'default-dt': 'model2',
7751 }
7752 testdir, dtb_list = self.SetupAlternateDts()
7753 data = self._DoReadFileDtb(
7754 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7755 entry_args=entry_args, extra_indirs=[testdir])[0]
7756
7757 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7758
7759 fit = fdt.Fdt.FromData(fit_data)
7760 fit.Scan()
7761
7762 cnode = fit.GetNode('/configurations')
7763 self.assertIn('default', cnode.props)
7764 self.assertEqual('config-2', cnode.props['default'].value)
7765
7766 for seq in range(1, 2):
7767 name = f'config-{seq}'
7768 fnode = fit.GetNode('/configurations/%s' % name)
7769 self.assertIsNotNone(fnode)
7770 self.assertIn('compatible', fnode.props.keys())
7771 expected = 'one' if seq == 1 else 'two'
7772 self.assertEqual(f'u-boot,model-{expected}',
7773 fnode.props['compatible'].value)
7774
Simon Glassa04b9942024-07-20 11:49:48 +01007775 def testFitFdtPhase(self):
7776 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7777 phase = 'tpl'
7778 entry_args = {
7779 f'{phase}-dtb': '1',
7780 f'{phase}-bss-pad': 'y',
7781 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7782 'of-list': 'model1 model2',
7783 'default-dt': 'model2',
7784 }
7785 testdir, dtb_list = self.SetupAlternateDts()
7786 data = self._DoReadFileDtb(
7787 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7788 entry_args=entry_args, extra_indirs=[testdir])[0]
7789 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7790 fit = fdt.Fdt.FromData(fit_data)
7791 fit.Scan()
7792
7793 # Check that each FDT has only the expected properties for the phase
7794 for seq in range(1, 2):
7795 fnode = fit.GetNode(f'/images/fdt-{seq}')
7796 self.assertIsNotNone(fnode)
7797 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7798 dtb.Scan()
7799
7800 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7801 # removal
7802 node = dtb.GetNode('/node')
7803 self.assertIsNotNone(node)
7804 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7805 node.props.keys())
7806
7807 # Make sure the other node is gone
7808 self.assertIsNone(dtb.GetNode('/node/other-node'))
7809
Simon Glassb553e8a2024-08-26 13:11:29 -06007810 def testMkeficapsuleMissing(self):
7811 """Test that binman complains if mkeficapsule is missing"""
7812 with self.assertRaises(ValueError) as e:
7813 self._DoTestFile('311_capsule.dts',
7814 force_missing_bintools='mkeficapsule')
7815 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7816 str(e.exception))
7817
7818 def testMkeficapsuleMissingOk(self):
7819 """Test that binman deals with mkeficapsule being missing"""
7820 with test_util.capture_sys_output() as (stdout, stderr):
7821 ret = self._DoTestFile('311_capsule.dts',
7822 force_missing_bintools='mkeficapsule',
7823 allow_missing=True)
7824 self.assertEqual(103, ret)
7825 err = stderr.getvalue()
7826 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7827
Simon Glass4b0f4142024-08-26 13:11:40 -06007828 def testSymbolsBase(self):
7829 """Test handling of symbols-base"""
7830 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7831 symbols_base=0)
7832
7833 def testSymbolsBaseExpanded(self):
7834 """Test handling of symbols-base with expanded entries"""
7835 entry_args = {
7836 'spl-dtb': '1',
7837 }
7838 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7839 U_BOOT_SPL_DTB_DATA, 0x38,
7840 entry_args=entry_args, use_expanded=True,
7841 symbols_base=0)
7842
Simon Glass3eb30a42024-08-26 13:11:42 -06007843 def testSymbolsCompressed(self):
7844 """Test binman complains about symbols from a compressed section"""
7845 with test_util.capture_sys_output() as (stdout, stderr):
7846 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7847 out = stdout.getvalue()
7848 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7849 out)
7850
Simon Glass9c25ef22024-08-26 13:11:43 -06007851 def testNxpImx8Image(self):
7852 """Test that binman can produce an iMX8 image"""
7853 self._DoTestFile('339_nxp_imx8.dts')
7854
Alice Guo1d334022025-04-28 18:37:39 +08007855 def testNxpHeaderDdrfw(self):
7856 """Test that binman can add a header to DDR PHY firmware images"""
7857 data = self._DoReadFile('346_nxp_ddrfw_imx95.dts')
7858 self.assertEqual(len(IMX_LPDDR_IMEM_DATA).to_bytes(4, 'little') +
7859 len(IMX_LPDDR_DMEM_DATA).to_bytes(4, 'little') +
7860 IMX_LPDDR_IMEM_DATA + IMX_LPDDR_DMEM_DATA, data)
7861
Alexander Kochetkova730a282024-09-16 11:24:46 +03007862 def testFitSignSimple(self):
7863 """Test that image with FIT and signature nodes can be signed"""
7864 if not elf.ELF_TOOLS:
7865 self.skipTest('Python elftools not available')
7866 entry_args = {
7867 'of-list': 'test-fdt1',
7868 'default-dt': 'test-fdt1',
7869 'atf-bl31-path': 'bl31.elf',
7870 }
7871 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7872 self._MakeInputFile("keys/rsa2048.key", data)
7873
7874 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7875 keys_subdir = os.path.join(self._indir, "keys")
7876 data = self._DoReadFileDtb(
7877 '340_fit_signature.dts',
7878 entry_args=entry_args,
7879 extra_indirs=[test_subdir, keys_subdir])[0]
7880
7881 dtb = fdt.Fdt.FromData(data)
7882 dtb.Scan()
7883
7884 conf = dtb.GetNode('/configurations/conf-uboot-1')
7885 self.assertIsNotNone(conf)
7886 signature = conf.FindNode('signature')
7887 self.assertIsNotNone(signature)
7888 self.assertIsNotNone(signature.props.get('value'))
7889
7890 images = dtb.GetNode('/images')
7891 self.assertIsNotNone(images)
7892 for subnode in images.subnodes:
7893 signature = subnode.FindNode('signature')
7894 self.assertIsNotNone(signature)
7895 self.assertIsNotNone(signature.props.get('value'))
7896
7897 def testFitSignKeyNotFound(self):
7898 """Test that missing keys raise an error"""
7899 if not elf.ELF_TOOLS:
7900 self.skipTest('Python elftools not available')
7901 entry_args = {
7902 'of-list': 'test-fdt1',
7903 'default-dt': 'test-fdt1',
7904 'atf-bl31-path': 'bl31.elf',
7905 }
7906 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7907 with self.assertRaises(ValueError) as e:
7908 self._DoReadFileDtb(
7909 '340_fit_signature.dts',
7910 entry_args=entry_args,
7911 extra_indirs=[test_subdir])[0]
7912 self.assertIn(
7913 'Filename \'rsa2048.key\' not found in input path',
7914 str(e.exception))
7915
7916 def testFitSignMultipleKeyPaths(self):
7917 """Test that keys found in multiple paths raise an error"""
7918 if not elf.ELF_TOOLS:
7919 self.skipTest('Python elftools not available')
7920 entry_args = {
7921 'of-list': 'test-fdt1',
7922 'default-dt': 'test-fdt1',
7923 'atf-bl31-path': 'bl31.elf',
7924 }
7925 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7926 self._MakeInputFile("keys1/rsa2048.key", data)
7927 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7928 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7929
7930 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7931 keys_subdir1 = os.path.join(self._indir, "keys1")
7932 keys_subdir2 = os.path.join(self._indir, "keys2")
7933 with self.assertRaises(ValueError) as e:
7934 self._DoReadFileDtb(
7935 '341_fit_signature.dts',
7936 entry_args=entry_args,
7937 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7938 self.assertIn(
7939 'Node \'/binman/fit\': multiple key paths found',
7940 str(e.exception))
7941
7942 def testFitSignNoSingatureNodes(self):
7943 """Test that fit,sign doens't raise error if no signature nodes found"""
7944 if not elf.ELF_TOOLS:
7945 self.skipTest('Python elftools not available')
7946 entry_args = {
7947 'of-list': 'test-fdt1',
7948 'default-dt': 'test-fdt1',
7949 'atf-bl31-path': 'bl31.elf',
7950 }
7951 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7952 self._DoReadFileDtb(
7953 '342_fit_signature.dts',
7954 entry_args=entry_args,
7955 extra_indirs=[test_subdir])[0]
7956
Simon Glassa360b8f2024-06-23 11:55:06 -06007957
Paul HENRYSff318462024-11-25 18:47:17 +01007958 def testSimpleFitEncryptedData(self):
7959 """Test an image with a FIT containing data to be encrypted"""
7960 data = tools.read_file(self.TestFile("aes256.bin"))
7961 self._MakeInputFile("keys/aes256.bin", data)
7962
7963 keys_subdir = os.path.join(self._indir, "keys")
7964 data = self._DoReadFileDtb(
7965 '343_fit_encrypt_data.dts',
7966 extra_indirs=[keys_subdir])[0]
7967
7968 fit = fdt.Fdt.FromData(data)
7969 fit.Scan()
7970
7971 # Extract the encrypted data and the Initialization Vector from the FIT
7972 node = fit.GetNode('/images/u-boot')
7973 subnode = fit.GetNode('/images/u-boot/cipher')
7974 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7975 byteorder='big')
7976 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7977
7978 # Retrieve the key name from the FIT removing any null byte
7979 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7980 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7981 key = file.read()
7982 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7983 enc_data = fit.GetProps(node)['data'].bytes
7984 outdir = tools.get_output_dir()
7985 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7986 tools.write_file(enc_data_file, enc_data)
7987 data_file = os.path.join(outdir, 'data.bin')
7988
7989 # Decrypt the encrypted data from the FIT and compare the data
7990 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7991 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7992 with open(data_file, 'r') as file:
7993 dec_data = file.read()
7994 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7995
7996 def testSimpleFitEncryptedDataMissingKey(self):
7997 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7998 with self.assertRaises(ValueError) as e:
7999 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
8000
8001 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
8002
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01008003 def testFitFdtName(self):
8004 """Test an image with an FIT with multiple FDT images using NAME"""
8005 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
8006
Neha Malcom Francisa25b4832025-03-17 10:24:20 +05308007 def testRemoveTemplate(self):
8008 """Test whether template is removed"""
8009 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
8010 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
8011 self._DoTestFile('346_remove_template.dts',
8012 force_missing_bintools='openssl',)
8013
Simon Glassac599912017-11-12 21:52:22 -07008014if __name__ == "__main__":
8015 unittest.main()