convert rockchip to use binman

patman fix for checkpatch
 binman optional entries, improved support for ELF symbols
 trace improvements
 minor fdt refactoring
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmPIpV4RHHNqZ0BjaHJv
 bWl1bS5vcmcACgkQfxc6PpAIreZuqwgA0UpYQEX6/MegzHSCIx3AMT4rCF1Ytitr
 LS4Cbvj1Q09Rt9jriW7wAV5AobVPwGf2L5SVcnWv2I9+MmypDIXEe8HIrt2fRFu9
 bzn/2GOzXczuXqPFa/CWOUwjvCzTb8Sl9NtRszrP5NvOzuN15x00ZUYaXFO7fgsB
 zZMzOKxemwjdtLaox+x+VIJ95HMDEkYrWTAqTPg74CNVSjRbbLNqNq0zqkHB8SnH
 ubgphtIKYItTeIXcfIa9V4LeQp0ZitkzSfAibX+nIPCMPg9jbG9MrQQ+VvSZDjnM
 y8wa8gFj47Ek+gGNFXMHIpO6tBd83uHRgtf2x+zhcovLELYnZ6fDGw==
 =1K6m
 -----END PGP SIGNATURE-----

Merge tag 'dm-pull-18jan23' of https://source.denx.de/u-boot/custodians/u-boot-dm

convert rockchip to use binman
patman fix for checkpatch
binman optional entries, improved support for ELF symbols
trace improvements
minor fdt refactoring
This commit is contained in:
Tom Rini 2023-01-19 09:46:57 -05:00
commit 53c47c59e6
78 changed files with 1617 additions and 537 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@
# Normal rules (sorted alphabetically)
#
.*
!.checkpatch.conf
*.a
*.asn1.[ch]
*.bin

View file

@ -1006,14 +1006,9 @@ ifeq ($(CONFIG_INIT_SP_RELATIVE)$(CONFIG_OF_SEPARATE),yy)
INPUTS-y += init_sp_bss_offset_check
endif
ifeq ($(CONFIG_ARCH_ROCKCHIP)$(CONFIG_SPL),yy)
# Binman image dependencies
ifeq ($(CONFIG_ARM64),y)
INPUTS-y += u-boot.itb
else
ifeq ($(CONFIG_ARCH_ROCKCHIP)_$(CONFIG_SPL_FRAMEWORK),y_)
INPUTS-y += u-boot.img
endif
endif
INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \
$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \
@ -1370,9 +1365,6 @@ $(U_BOOT_ITS): $(subst ",,$(CONFIG_SPL_FIT_SOURCE))
else
ifneq ($(CONFIG_USE_SPL_FIT_GENERATOR),)
U_BOOT_ITS := u-boot.its
ifeq ($(CONFIG_SPL_FIT_GENERATOR),"arch/arm/mach-rockchip/make_fit_atf.py")
U_BOOT_ITS_DEPS += u-boot
endif
$(U_BOOT_ITS): $(U_BOOT_ITS_DEPS) FORCE
$(srctree)/$(CONFIG_SPL_FIT_GENERATOR) \
$(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) > $@
@ -1477,7 +1469,6 @@ OBJCOPYFLAGS_u-boot-with-spl.bin = -I binary -O binary \
u-boot-with-spl.bin: $(SPL_IMAGE) $(SPL_PAYLOAD) FORCE
$(call if_changed,pad_cat)
ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy)
MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE)

View file

@ -82,7 +82,7 @@ unsigned long get_timer(unsigned long base)
return time_ms - base;
}
unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
unsigned long notrace timer_get_us(void)
{
static unsigned long base_time_us;

View file

@ -17,7 +17,7 @@ DECLARE_GLOBAL_DATA_PTR;
/*
* Generic timer implementation of get_tbclk()
*/
unsigned long get_tbclk(void)
unsigned long notrace get_tbclk(void)
{
unsigned long cntfrq;
asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq));
@ -78,7 +78,7 @@ unsigned long timer_read_counter(void)
/*
* timer_read_counter() using the Arm Generic Timer (aka arch timer).
*/
unsigned long timer_read_counter(void)
unsigned long notrace timer_read_counter(void)
{
unsigned long cntpct;
@ -89,7 +89,7 @@ unsigned long timer_read_counter(void)
}
#endif
uint64_t get_ticks(void)
uint64_t notrace get_ticks(void)
{
unsigned long ticks = timer_read_counter();

View file

@ -17,7 +17,7 @@
&binman {
simple-bin {
blob {
fit {
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
};
};

View file

@ -46,14 +46,14 @@
&binman {
simple-bin {
blob {
fit {
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
};
};
#ifdef CONFIG_ROCKCHIP_SPI_IMAGE
simple-bin-spi {
blob {
fit {
/* same as u-boot,spl-payload-offset */
offset = <0x80000>;
};

View file

@ -62,6 +62,7 @@
#if defined(CONFIG_ROCKCHIP_SPI_IMAGE) && defined(CONFIG_HAS_ROM)
&binman {
multiple-images;
rom {
filename = "u-boot.rom";
size = <0x400000>;
@ -82,7 +83,7 @@
};
};
};
#endif
#endif /* CONFIG_ROCKCHIP_SPI_IMAGE && CONFIG_HAS_ROM */
&cru {
u-boot,dm-pre-reloc;

View file

@ -30,14 +30,79 @@
};
};
#ifdef CONFIG_ARM64
blob {
#if defined(CONFIG_SPL_FIT) && defined(CONFIG_ARM64)
fit: fit {
description = "FIT image for U-Boot with bl31 (TF-A)";
#address-cells = <1>;
fit,fdt-list = "of-list";
filename = "u-boot.itb";
fit,external-offset = <CONFIG_FIT_EXTERNAL_OFFSET>;
offset = <CONFIG_SPL_PAD_TO>;
images {
u-boot {
description = "U-Boot (64-bit)";
type = "standalone";
os = "U-Boot";
arch = "arm64";
compression = "none";
load = <CONFIG_TEXT_BASE>;
entry = <CONFIG_TEXT_BASE>;
u-boot-nodtb {
};
};
@atf-SEQ {
fit,operation = "split-elf";
description = "ARM Trusted Firmware";
type = "firmware";
arch = "arm64";
os = "arm-trusted-firmware";
compression = "none";
fit,load;
fit,entry;
fit,data;
atf-bl31 {
};
};
@tee-SEQ {
fit,operation = "split-elf";
description = "TEE";
type = "tee";
arch = "arm64";
os = "tee";
compression = "none";
fit,load;
fit,entry;
fit,data;
tee-os {
optional;
};
};
@fdt-SEQ {
description = "fdt-NAME";
compression = "none";
type = "flat_dt";
};
};
configurations {
default = "@config-DEFAULT-SEQ";
@config-SEQ {
description = "NAME.dtb";
fdt = "fdt-SEQ";
firmware = "u-boot";
fit,loadables;
};
};
};
#else
u-boot-img {
#endif
offset = <CONFIG_SPL_PAD_TO>;
};
#endif
};
#ifdef CONFIG_ROCKCHIP_SPI_IMAGE
@ -59,7 +124,8 @@
};
#ifdef CONFIG_ARM64
blob {
fit {
type = "blob";
filename = "u-boot.itb";
#else
u-boot-img {
@ -68,6 +134,6 @@
offset = <CONFIG_SYS_SPI_U_BOOT_OFFS>;
};
};
#endif
#endif /* CONFIG_ROCKCHIP_SPI_IMAGE */
};
#endif
#endif /* CONFIG_SPL */

View file

@ -248,7 +248,7 @@ static inline char *s5p_get_cpu_name(void)
}
#define IS_SAMSUNG_TYPE(type, id) \
static inline int __attribute__((no_instrument_function)) cpu_is_##type(void) \
static inline int notrace cpu_is_##type(void) \
{ \
return (s5p_cpu_id >> 12) == id; \
}
@ -257,7 +257,7 @@ IS_SAMSUNG_TYPE(exynos4, 0x4)
IS_SAMSUNG_TYPE(exynos5, 0x5)
#define IS_EXYNOS_TYPE(type, id) \
static inline int __attribute__((no_instrument_function)) \
static inline int notrace \
proid_is_##type(void) \
{ \
return s5p_cpu_id == id; \
@ -272,7 +272,7 @@ IS_EXYNOS_TYPE(exynos5422, 0x5422)
#define proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422())
#define SAMSUNG_BASE(device, base) \
static inline unsigned long __attribute__((no_instrument_function)) \
static inline unsigned long notrace \
samsung_get_base_##device(void) \
{ \
if (cpu_is_exynos4()) { \

View file

@ -1,267 +0,0 @@
#!/usr/bin/env python3
"""
# SPDX-License-Identifier: GPL-2.0+
#
# A script to generate FIT image source for rockchip boards
# with ARM Trusted Firmware
# and multiple device trees (given on the command line)
#
# usage: $0 <dt_name> [<dt_name> [<dt_name] ...]
"""
import os
import sys
import getopt
import logging
import struct
DT_HEADER = """
/*
* This is a generated file.
*/
/dts-v1/;
/ {
description = "FIT image for U-Boot with bl31 (TF-A)";
#address-cells = <1>;
images {
"""
DT_UBOOT = """
uboot {
description = "U-Boot (64-bit)";
data = /incbin/("u-boot-nodtb.bin");
type = "standalone";
os = "U-Boot";
arch = "arm64";
compression = "none";
load = <0x%08x>;
};
"""
DT_IMAGES_NODE_END = """ };
"""
DT_END = "};"
def append_bl31_node(file, atf_index, phy_addr, elf_entry):
# Append BL31 DT node to input FIT dts file.
data = 'bl31_0x%08x.bin' % phy_addr
file.write('\t\tatf_%d {\n' % atf_index)
file.write('\t\t\tdescription = \"ARM Trusted Firmware\";\n')
file.write('\t\t\tdata = /incbin/("%s");\n' % data)
file.write('\t\t\ttype = "firmware";\n')
file.write('\t\t\tarch = "arm64";\n')
file.write('\t\t\tos = "arm-trusted-firmware";\n')
file.write('\t\t\tcompression = "none";\n')
file.write('\t\t\tload = <0x%08x>;\n' % phy_addr)
if atf_index == 1:
file.write('\t\t\tentry = <0x%08x>;\n' % elf_entry)
file.write('\t\t};\n')
file.write('\n')
def append_tee_node(file, atf_index, phy_addr, elf_entry):
# Append TEE DT node to input FIT dts file.
data = 'tee_0x%08x.bin' % phy_addr
file.write('\t\tatf_%d {\n' % atf_index)
file.write('\t\t\tdescription = \"TEE\";\n')
file.write('\t\t\tdata = /incbin/("%s");\n' % data)
file.write('\t\t\ttype = "tee";\n')
file.write('\t\t\tarch = "arm64";\n')
file.write('\t\t\tos = "tee";\n')
file.write('\t\t\tcompression = "none";\n')
file.write('\t\t\tload = <0x%08x>;\n' % phy_addr)
file.write('\t\t\tentry = <0x%08x>;\n' % elf_entry)
file.write('\t\t};\n')
file.write('\n')
def append_fdt_node(file, dtbs):
# Append FDT nodes.
cnt = 1
for dtb in dtbs:
dtname = os.path.basename(dtb)
file.write('\t\tfdt_%d {\n' % cnt)
file.write('\t\t\tdescription = "%s";\n' % dtname)
file.write('\t\t\tdata = /incbin/("%s");\n' % dtb)
file.write('\t\t\ttype = "flat_dt";\n')
file.write('\t\t\tcompression = "none";\n')
file.write('\t\t};\n')
file.write('\n')
cnt = cnt + 1
def append_conf_section(file, cnt, dtname, segments):
file.write('\t\tconfig_%d {\n' % cnt)
file.write('\t\t\tdescription = "%s";\n' % dtname)
file.write('\t\t\tfirmware = "atf_1";\n')
file.write('\t\t\tloadables = "uboot"')
if segments > 1:
file.write(',')
for i in range(1, segments):
file.write('"atf_%d"' % (i + 1))
if i != (segments - 1):
file.write(',')
else:
file.write(';\n')
if segments <= 1:
file.write(';\n')
file.write('\t\t\tfdt = "fdt_%d";\n' % cnt)
file.write('\t\t};\n')
file.write('\n')
def append_conf_node(file, dtbs, segments):
# Append configeration nodes.
cnt = 1
file.write('\tconfigurations {\n')
file.write('\t\tdefault = "config_1";\n')
for dtb in dtbs:
dtname = os.path.basename(dtb)
append_conf_section(file, cnt, dtname, segments)
cnt = cnt + 1
file.write('\t};\n')
file.write('\n')
def generate_atf_fit_dts_uboot(fit_file, uboot_file_name):
segments = unpack_elf(uboot_file_name)
if len(segments) != 1:
raise ValueError("Invalid u-boot ELF image '%s'" % uboot_file_name)
index, entry, p_paddr, data = segments[0]
fit_file.write(DT_UBOOT % p_paddr)
def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, tee_file_name, dtbs_file_name):
segments = unpack_elf(bl31_file_name)
for index, entry, paddr, data in segments:
append_bl31_node(fit_file, index + 1, paddr, entry)
num_segments = len(segments)
if tee_file_name:
tee_segments = unpack_tee_file(tee_file_name)
for index, entry, paddr, data in tee_segments:
append_tee_node(fit_file, num_segments + index + 1, paddr, entry)
num_segments = num_segments + len(tee_segments)
append_fdt_node(fit_file, dtbs_file_name)
fit_file.write(DT_IMAGES_NODE_END)
append_conf_node(fit_file, dtbs_file_name, num_segments)
def generate_atf_fit_dts(fit_file_name, bl31_file_name, tee_file_name, uboot_file_name, dtbs_file_name):
# Generate FIT script for ATF image.
if fit_file_name != sys.stdout:
fit_file = open(fit_file_name, "wb")
else:
fit_file = sys.stdout
fit_file.write(DT_HEADER)
generate_atf_fit_dts_uboot(fit_file, uboot_file_name)
generate_atf_fit_dts_bl31(fit_file, bl31_file_name, tee_file_name, dtbs_file_name)
fit_file.write(DT_END)
if fit_file_name != sys.stdout:
fit_file.close()
def generate_atf_binary(bl31_file_name):
for index, entry, paddr, data in unpack_elf(bl31_file_name):
file_name = 'bl31_0x%08x.bin' % paddr
with open(file_name, "wb") as atf:
atf.write(data)
def generate_tee_binary(tee_file_name):
if tee_file_name:
for index, entry, paddr, data in unpack_tee_file(tee_file_name):
file_name = 'tee_0x%08x.bin' % paddr
with open(file_name, "wb") as atf:
atf.write(data)
def unpack_elf(filename):
with open(filename, 'rb') as file:
elf = file.read()
if elf[0:7] != b'\x7fELF\x02\x01\x01' or elf[18:20] != b'\xb7\x00':
raise ValueError("Invalid arm64 ELF file '%s'" % filename)
e_entry, e_phoff = struct.unpack_from('<2Q', elf, 0x18)
e_phentsize, e_phnum = struct.unpack_from('<2H', elf, 0x36)
segments = []
for index in range(e_phnum):
offset = e_phoff + e_phentsize * index
p_type, p_flags, p_offset = struct.unpack_from('<LLQ', elf, offset)
if p_type == 1: # PT_LOAD
p_paddr, p_filesz = struct.unpack_from('<2Q', elf, offset + 0x18)
if p_filesz > 0:
p_data = elf[p_offset:p_offset + p_filesz]
segments.append((index, e_entry, p_paddr, p_data))
return segments
def unpack_tee_file(filename):
if filename.endswith('.elf'):
return unpack_elf(filename)
with open(filename, 'rb') as file:
bin = file.read()
segments = []
if bin[0:5] == b'OPTE\x01':
# OP-TEE v1 format (tee.bin)
init_sz, start_hi, start_lo, _, paged_sz = struct.unpack_from('<5I',
bin,
0x8)
if paged_sz != 0:
raise ValueError("OP-TEE paged mode not supported")
e_entry = (start_hi << 32) + start_lo
p_addr = e_entry
p_data = bin[0x1c:]
if len(p_data) != init_sz:
raise ValueError("Invalid file '%s': size mismatch "
"(expected %d, have %d)" % (filename, init_sz,
len(p_data)))
segments.append((0, e_entry, p_addr, p_data))
else:
raise ValueError("Unknown format for TEE file '%s'" % filename)
return segments
def main():
uboot_elf = "./u-boot"
fit_its = sys.stdout
if "BL31" in os.environ:
bl31_elf=os.getenv("BL31");
elif os.path.isfile("./bl31.elf"):
bl31_elf = "./bl31.elf"
else:
os.system("echo 'int main(){}' > bl31.c")
os.system("${CROSS_COMPILE}gcc -c bl31.c -o bl31.elf")
bl31_elf = "./bl31.elf"
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.warning(' BL31 file bl31.elf NOT found, resulting binary is non-functional')
logging.warning(' Please read Building section in doc/README.rockchip')
if "TEE" in os.environ:
tee_file = os.getenv("TEE")
elif os.path.isfile("./tee.bin"):
tee_file = "./tee.bin"
elif os.path.isfile("./tee.elf"):
tee_file = "./tee.elf"
else:
tee_file = ""
opts, args = getopt.getopt(sys.argv[1:], "o:u:b:t:h")
for opt, val in opts:
if opt == "-o":
fit_its = val
elif opt == "-u":
uboot_elf = val
elif opt == "-b":
bl31_elf = val
elif opt == "-t":
tee_file = val
elif opt == "-h":
print(__doc__)
sys.exit(2)
dtbs = args
generate_atf_fit_dts(fit_its, bl31_elf, tee_file, uboot_elf, dtbs)
generate_atf_binary(bl31_elf)
generate_tee_binary(tee_file)
if __name__ == "__main__":
main()

View file

@ -4,6 +4,7 @@
*/
#include <common.h>
#include <bootstage.h>
#include <debug_uart.h>
#include <dm.h>
#include <hang.h>
@ -70,15 +71,15 @@ void board_init_f(ulong dummy)
U_BOOT_TIME ")\n");
#endif
#endif
/* Init secure timer */
rockchip_stimer_init();
ret = spl_early_init();
if (ret) {
debug("spl_early_init() failed: %d\n", ret);
hang();
}
/* Init secure timer */
rockchip_stimer_init();
/* Init ARM arch timer */
if (IS_ENABLED(CONFIG_SYS_ARCH_TIMER))
timer_init();
@ -93,6 +94,15 @@ void board_init_f(ulong dummy)
int board_return_to_bootrom(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
#ifdef CONFIG_BOOTSTAGE_STASH
int ret;
bootstage_mark_name(BOOTSTAGE_ID_END_TPL, "end tpl");
ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
CONFIG_BOOTSTAGE_STASH_SIZE);
if (ret)
debug("Failed to stash bootstage: err=%d\n", ret);
#endif
back_to_bootrom(BROM_BOOT_NEXTSTAGE);
return 0;

View file

@ -137,7 +137,7 @@ struct arch_global_data {
#define DECLARE_GLOBAL_DATA_PTR extern struct global_data *global_data_ptr
# else
static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void)
static inline notrace gd_t *get_fs_gd_ptr(void)
{
gd_t *gd_ptr;

View file

@ -71,7 +71,7 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
#define EAX_EDX_RET(val, low, high) "=A" (val)
#endif
static inline __attribute__((no_instrument_function))
static inline notrace
unsigned long long native_read_msr(unsigned int msr)
{
DECLARE_ARGS(val, low, high);

View file

@ -108,7 +108,7 @@ void board_init_f_r(void) __attribute__ ((noreturn));
int arch_misc_init(void);
/* Read the time stamp counter */
static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
static inline notrace uint64_t rdtsc(void)
{
uint32_t high, low;
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));

View file

@ -282,12 +282,11 @@ config SPL_FIT_SOURCE
config USE_SPL_FIT_GENERATOR
bool "Use a script to generate the .its script"
depends on SPL_FIT
default y if !ARCH_SUNXI && !RISCV
default y if SPL_FIT && ARCH_ZYNQMP
config SPL_FIT_GENERATOR
string ".its file generator script for U-Boot FIT image"
depends on USE_SPL_FIT_GENERATOR
default "arch/arm/mach-rockchip/make_fit_atf.py" if SPL_LOAD_FIT && ARCH_ROCKCHIP
default "arch/arm/mach-zynqmp/mkimage_fit_atf.sh" if SPL_LOAD_FIT && ARCH_ZYNQMP
help
Specifies a (platform specific) script file to generate the FIT

View file

@ -599,6 +599,7 @@ static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
debug("Ignoring compatible = %s property\n",
compatible);
}
return 0;
ret = fpga_load(devnum, (void *)fpga_image->load_addr,
fpga_image->size, BIT_FULL, flags);

View file

@ -179,3 +179,4 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0451
CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_PHANDLE_CHECK_SEQ=y

View file

@ -120,3 +120,4 @@ CONFIG_WDT=y
CONFIG_SHA384=y
CONFIG_HEXDUMP=y
# CONFIG_EFI_LOADER is not set
CONFIG_PHANDLE_CHECK_SEQ=y

View file

@ -29,6 +29,7 @@ CONFIG_SILENT_CONSOLE=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_SPL_PAD_TO=0x7f8000
CONFIG_SPL_NO_BSS_LIMIT=y
# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
CONFIG_SPL_STACK=0xff718000
CONFIG_SPL_STACK_R=y

View file

@ -9,6 +9,7 @@ CONFIG_ENV_OFFSET=0x3F8000
CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64"
CONFIG_ROCKCHIP_RK3399=y
CONFIG_TARGET_ROCKPRO64_RK3399=y
CONFIG_BOOTSTAGE_STASH_ADDR=0xff8e0000
CONFIG_DEBUG_UART_BASE=0xFF1A0000
CONFIG_DEBUG_UART_CLOCK=24000000
CONFIG_SPL_SPI_FLASH_SUPPORT=y
@ -17,6 +18,12 @@ CONFIG_SYS_LOAD_ADDR=0x800800
CONFIG_DEBUG_UART=y
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x300000
CONFIG_BOOTSTAGE=y
CONFIG_SPL_BOOTSTAGE=y
CONFIG_TPL_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10
CONFIG_BOOTSTAGE_STASH=y
CONFIG_USE_PREBOOT=y
CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-rockpro64.dtb"
CONFIG_DISPLAY_BOARDINFO_LATE=y
@ -40,6 +47,7 @@ CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TIME=y
CONFIG_CMD_BOOTSTAGE=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
CONFIG_ENV_IS_IN_SPI_FLASH=y

View file

@ -79,3 +79,4 @@ CONFIG_TIMER=y
CONFIG_MCHP_PIT64B_TIMER=y
CONFIG_OF_LIBFDT_OVERLAY=y
# CONFIG_EFI_LOADER_HII is not set
CONFIG_PHANDLE_CHECK_SEQ=y

View file

@ -79,3 +79,4 @@ CONFIG_TIMER=y
CONFIG_MCHP_PIT64B_TIMER=y
CONFIG_OF_LIBFDT_OVERLAY=y
# CONFIG_EFI_LOADER_HII is not set
CONFIG_PHANDLE_CHECK_SEQ=y

View file

@ -185,7 +185,7 @@ this produces sensible results for your board. Suitable sources for
this timer include high resolution timers, PWMs or profile timers if
available. Most modern SOCs have a suitable timer for this. Make sure
that you mark this timer (and anything it calls) with
__attribute__((no_instrument_function)) so that the trace library can
notrace so that the trace library can
use it without causing an infinite loop.

View file

@ -403,13 +403,6 @@ static int __maybe_unused pinctrl_post_bind(struct udevice *dev)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
/*
* Make sure that the pinctrl driver gets probed after binding
* as some pinctrl drivers also register the GPIO driver during
* probe, and if they are not probed GPIO-s are not registered.
*/
dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
if (!ops) {
dev_dbg(dev, "ops is not set. Do not bind.\n");
return -EINVAL;

View file

@ -554,15 +554,6 @@ uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
*/
int fdtdec_get_is_enabled(const void *blob, int node);
/**
* Make sure we have a valid fdt available to control U-Boot.
*
* If not, a message is printed to the console if the console is ready.
*
* Return: 0 if all ok, -1 if not
*/
int fdtdec_prepare_fdt(void);
/**
* Checks that we have a valid fdt available to control U-Boot.

View file

@ -316,7 +316,7 @@ config BITREVERSE
config TRACE
bool "Support for tracing of function calls and timing"
imply CMD_TRACE
select TIMER_EARLY
imply TIMER_EARLY
help
Enables function tracing within U-Boot. This allows recording of call
traces including timing information. The command can write data to
@ -422,6 +422,7 @@ config TPM
config SPL_TPM
bool "Trusted Platform Module (TPM) Support in SPL"
depends on SPL_DM
imply SPL_CRC8
help
This enables support for TPMs which can be used to provide security
features for your board. The TPM can be connected via LPC or I2C
@ -617,6 +618,23 @@ config SPL_MD5
security applications, but it can be useful for providing a quick
checksum of a block of data.
config CRC8
def_bool y
help
Enables CRC8 support in U-Boot. This is normally required. CRC8 is
a simple and fast checksumming algorithm which does a bytewise
checksum with feedback to produce an 8-bit result. The code is small
and it does not require a lookup table (unlike CRC32).
config SPL_CRC8
bool "Support CRC8 in SPL"
depends on SPL
help
Enables CRC8 support in SPL. This is not normally required. CRC8 is
a simple and fast checksumming algorithm which does a bytewise
checksum with feedback to produce an 8-bit result. The code is small
and it does not require a lookup table (unlike CRC32).
config CRC32
def_bool y
help
@ -1042,6 +1060,13 @@ config LMB_RESERVED_REGIONS
Define the number of supported reserved regions in the library logical
memory blocks.
config PHANDLE_CHECK_SEQ
bool "Enable phandle check while getting sequence number"
help
When there are multiple device tree nodes with same name,
enable this config option to distinguish them using
phandles in fdtdec_get_alias_seq() function.
endmenu
menu "FWU Multi Bank Updates"

View file

@ -57,12 +57,13 @@ endif
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o
ifeq ($(CONFIG_$(SPL_TPL_)TPM),y)
obj-y += crc8.o
obj-$(CONFIG_TPM) += tpm_api.o
obj-$(CONFIG_TPM_V1) += tpm-v1.o
obj-$(CONFIG_TPM_V2) += tpm-v2.o
endif
obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o
obj-y += crypto/
obj-$(CONFIG_$(SPL_TPL_)GENERATE_ACPI_TABLE) += acpi/

View file

@ -100,7 +100,7 @@ void *memset(void *s, int c, size_t n)
* func_ptr: Pointer to function being entered
* caller: Pointer to function which called this function
*/
void __attribute__((no_instrument_function))
void notrace
__cyg_profile_func_enter(void *func_ptr, void *caller)
{
}
@ -116,7 +116,7 @@ __cyg_profile_func_enter(void *func_ptr, void *caller)
* func_ptr: Pointer to function being entered
* caller: Pointer to function which called this function
*/
void __attribute__((no_instrument_function))
void notrace
__cyg_profile_func_exit(void *func_ptr, void *caller)
{
}

View file

@ -13,6 +13,7 @@
#include <log.h>
#include <malloc.h>
#include <net.h>
#include <spl.h>
#include <env.h>
#include <errno.h>
#include <fdtdec.h>
@ -518,8 +519,11 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
* Adding an extra check to distinguish DT nodes with
* same name
*/
if (offset != fdt_path_offset(blob, prop))
continue;
if (IS_ENABLED(CONFIG_PHANDLE_CHECK_SEQ)) {
if (fdt_get_phandle(blob, offset) !=
fdt_get_phandle(blob, fdt_path_offset(blob, prop)))
continue;
}
val = trailing_strtol(name);
if (val != -1) {
@ -586,6 +590,34 @@ int fdtdec_get_chosen_node(const void *blob, const char *name)
return fdt_path_offset(blob, prop);
}
/**
* fdtdec_prepare_fdt() - Check we have a valid fdt available to control U-Boot
*
* @blob: Blob to check
*
* If not, a message is printed to the console if the console is ready.
*
* Return: 0 if all ok, -ENOENT if not
*/
static int fdtdec_prepare_fdt(const void *blob)
{
if (!blob || ((uintptr_t)blob & 3) || fdt_check_header(blob)) {
if (spl_phase() <= PHASE_SPL) {
puts("Missing DTB\n");
} else {
printf("No valid device tree binary found at %p\n",
blob);
if (_DEBUG && blob) {
printf("fdt_blob=%p\n", blob);
print_buffer((ulong)blob, blob, 4, 32, 0);
}
}
return -ENOENT;
}
return 0;
}
int fdtdec_check_fdt(void)
{
/*
@ -594,34 +626,7 @@ int fdtdec_check_fdt(void)
* FDT (prior to console ready) will need to make their own
* arrangements and do their own checks.
*/
assert(!fdtdec_prepare_fdt());
return 0;
}
/*
* This function is a little odd in that it accesses global data. At some
* point if the architecture board.c files merge this will make more sense.
* Even now, it is common code.
*/
int fdtdec_prepare_fdt(void)
{
if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
fdt_check_header(gd->fdt_blob)) {
#ifdef CONFIG_SPL_BUILD
puts("Missing DTB\n");
#else
printf("No valid device tree binary found at %p\n",
gd->fdt_blob);
# ifdef DEBUG
if (gd->fdt_blob) {
printf("fdt_blob=%p\n", gd->fdt_blob);
print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
32, 0);
}
# endif
#endif
return -1;
}
assert(!fdtdec_prepare_fdt(gd->fdt_blob));
return 0;
}
@ -1229,6 +1234,29 @@ static void *fdt_find_separate(void)
#else
/* FDT is at end of image */
fdt_blob = (ulong *)&_end;
if (_DEBUG && !fdtdec_prepare_fdt(fdt_blob)) {
int stack_ptr;
const void *top = fdt_blob + fdt_totalsize(fdt_blob);
/*
* Perform a sanity check on the memory layout. If this fails,
* it indicates that the device tree is positioned above the
* global data pointer or the stack pointer. This should not
* happen.
*
* If this fails, check that SYS_INIT_SP_ADDR has enough space
* below it for SYS_MALLOC_F_LEN and global_data, as well as the
* stack, without overwriting the device tree or U-Boot itself.
* Since the device tree is sitting at _end (the start of the
* BSS region), we need the top of the device tree to be below
* any memory allocated by board_init_f_alloc_reserve().
*/
if (top > (void *)gd || top > (void *)&stack_ptr) {
printf("FDT %p gd %p\n", fdt_blob, gd);
panic("FDT overlap");
}
}
#endif
return fdt_blob;
@ -1666,7 +1694,7 @@ int fdtdec_setup(void)
if (CONFIG_IS_ENABLED(MULTI_DTB_FIT))
setup_multi_dtb_fit();
ret = fdtdec_prepare_fdt();
ret = fdtdec_prepare_fdt(gd->fdt_blob);
if (!ret)
ret = fdtdec_board_setup(gd->fdt_blob);
oftree_reset();
@ -1698,7 +1726,7 @@ int fdtdec_resetup(int *rescan)
*rescan = 1;
gd->fdt_blob = fdt_blob;
return fdtdec_prepare_fdt();
return fdtdec_prepare_fdt(fdt_blob);
}
/*

View file

@ -40,7 +40,8 @@ struct trace_hdr {
int max_depth;
};
static struct trace_hdr *hdr; /* Pointer to start of trace buffer */
/* Pointer to start of trace buffer */
static struct trace_hdr *hdr __section(".data");
static inline uintptr_t __attribute__((no_instrument_function))
func_ptr_to_num(void *func_ptr)
@ -68,7 +69,7 @@ static volatile gd_t *trace_gd;
/**
* trace_save_gd() - save the value of the gd register
*/
static void __attribute__((no_instrument_function)) trace_save_gd(void)
static void notrace trace_save_gd(void)
{
trace_gd = gd;
}
@ -81,7 +82,7 @@ static void __attribute__((no_instrument_function)) trace_save_gd(void)
* have to set the gd register to the U-Boot value when entering a trace
* point and set it back to the application value when exiting the trace point.
*/
static void __attribute__((no_instrument_function)) trace_swap_gd(void)
static void notrace trace_swap_gd(void)
{
volatile gd_t *temp_gd = trace_gd;
@ -91,18 +92,17 @@ static void __attribute__((no_instrument_function)) trace_swap_gd(void)
#else
static void __attribute__((no_instrument_function)) trace_save_gd(void)
static void notrace trace_save_gd(void)
{
}
static void __attribute__((no_instrument_function)) trace_swap_gd(void)
static void notrace trace_swap_gd(void)
{
}
#endif
static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
void *caller, ulong flags)
static void notrace add_ftrace(void *func_ptr, void *caller, ulong flags)
{
if (hdr->depth > hdr->depth_limit) {
hdr->ftrace_too_deep_count++;
@ -118,7 +118,7 @@ static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
hdr->ftrace_count++;
}
static void __attribute__((no_instrument_function)) add_textbase(void)
static void notrace add_textbase(void)
{
if (hdr->ftrace_count < hdr->ftrace_size) {
struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count];
@ -139,8 +139,7 @@ static void __attribute__((no_instrument_function)) add_textbase(void)
* @func_ptr: pointer to function being entered
* @caller: pointer to function which called this function
*/
void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
void *func_ptr, void *caller)
void notrace __cyg_profile_func_enter(void *func_ptr, void *caller)
{
if (trace_enabled) {
int func;
@ -167,8 +166,7 @@ void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
* @func_ptr: pointer to function being entered
* @caller: pointer to function which called this function
*/
void __attribute__((no_instrument_function)) __cyg_profile_func_exit(
void *func_ptr, void *caller)
void notrace __cyg_profile_func_exit(void *func_ptr, void *caller)
{
if (trace_enabled) {
trace_swap_gd();
@ -327,7 +325,7 @@ void trace_print_stats(void)
puts(" calls not traced due to depth\n");
}
void __attribute__((no_instrument_function)) trace_set_enabled(int enabled)
void notrace trace_set_enabled(int enabled)
{
trace_enabled = enabled != 0;
}
@ -339,8 +337,7 @@ void __attribute__((no_instrument_function)) trace_set_enabled(int enabled)
* @buff_size: Size of trace buffer
* Return: 0 if ok
*/
int __attribute__((no_instrument_function)) trace_init(void *buff,
size_t buff_size)
int notrace trace_init(void *buff, size_t buff_size)
{
ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
size_t needed;
@ -404,7 +401,7 @@ int __attribute__((no_instrument_function)) trace_init(void *buff,
*
* Return: 0 if ok, -ENOSPC if not enough memory is available
*/
int __attribute__((no_instrument_function)) trace_early_init(void)
int notrace trace_early_init(void)
{
ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
size_t buff_size = CONFIG_TRACE_EARLY_SIZE;

View file

@ -487,6 +487,14 @@ For x86 devices (with the end-at-4gb property) this base address is not added
since it is assumed that images are XIP and the offsets already include the
address.
While U-Boot's symbol updating is handled automatically by the u-boot-spl
entry type (and others), it is possible to use this feature with any blob. To
do this, add a `write-symbols` (boolean) property to the node, set the ELF
filename using `elf-filename` and set 'elf-base-sym' to the base symbol for the
start of the binary image (this defaults to `__image_copy_start` which is what
U-Boot uses). See `testBlobSymbol()` for an example.
.. _binman_fdt:
Access to binman entry offsets at run time (fdt)
------------------------------------------------
@ -689,6 +697,15 @@ no-expanded:
`no-expanded` property disables this just for a single entry. Put the
`no-expanded` boolean property in the node to select this behaviour.
optional:
External blobs are normally required to be present for the image to be
built (but see `External blobs`_). This properly allows an entry to be
optional, so that when it is cannot be found, this problem is ignored and
an empty file is used for this blob. This should be used only when the blob
is entirely optional and is not needed for correct operation of the image.
Note that missing, optional blobs do not produce a non-zero exit code from
binman, although it does show a warning about the missing external blob.
The attributes supported for images and sections are described below. Several
are similar to those for entries.
@ -782,6 +799,37 @@ align-default:
symlink:
Adds a symlink to the image with string given in the symlink property.
overlap:
Indicates that this entry overlaps with others in the same section. These
entries should appear at the end of the section. Overlapping entries are not
packed with other entries, but their contents are written over other entries
in the section. Overlapping entries must have an explicit offset and size.
write-symbols:
Indicates that the blob should be updated with symbol values calculated by
binman. This is automatic for certain entry types, e.g. `u-boot-spl`. See
binman_syms_ for more information.
elf-filename:
Sets the file name of a blob's associated ELF file. For example, if the
blob is `zephyr.bin` then the ELF file may be `zephyr.elf`. This allows
binman to locate symbols and understand the structure of the blob. See
binman_syms_ for more information.
elf-base-sym:
Sets the name of the ELF symbol that points to the start of a blob. For
U-Boot this is `__image_copy_start` and that is the default used by binman
if this property is missing. For other projects, a difference symbol may be
needed. Add this symbol to the properties for the blob so that symbols can
be read correctly. See binman_syms_ for more information.
offset-from-elf:
Sets the offset of an entry based on a symbol value in an another entry.
The format is <&phandle>, "sym_name", <offset> where phandle is the entry
containing the blob (with associated ELF file providing symbols), <sym_name>
is the symbol to lookup (relative to elf-base-sym) and <offset> is an offset
to add to that value.
Examples of the above options can be found in the tests. See the
tools/binman/test directory.
@ -836,6 +884,11 @@ name-prefix:
renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
distinguish binaries with otherwise identical names.
filename:
This allows the contents of the section to be written to a file in the
output directory. This can sometimes be useful to use the data in one
section in different image, since there is currently no way to share data
beteen images other than through files.
Image Properties
----------------
@ -1007,6 +1060,28 @@ For the BSS case, a 'spl-bss-pad' entry arg controls whether it is present. All
entry args are provided by the U-Boot Makefile.
Optional entries
----------------
Some entries need to exist only if certain conditions are met. For example, an
entry may want to appear in the image only if a file has a particular format.
Obviously the entry must exist in the image description for it to be processed
at all, so a way needs to be found to have the entry remove itself.
To handle this, when entry.ObtainContents() is called, the entry can call
entry.mark_absent() to mark itself as absent, passing a suitable message as the
reason.
Any absent entries are dropped immediately after ObtainContents() has been
called on all entries.
It is not possible for an entry to mark itself absent at any other point in the
processing. It must happen in the ObtainContents() method.
The effect is as if the entry had never been present at all, since the image
is packed without it and it disappears from the list of entries.
Compression
-----------
@ -1683,7 +1758,8 @@ implementation of Pack() is usually sufficient.
Note: for sections, this also checks that the entries do not overlap, nor extend
outside the section. If the section does not have a defined size, the size is
set large enough to hold all the entries.
set large enough to hold all the entries. For entries that are explicitly marked
as overlapping, this check is skipped.
6. SetImagePos() - sets the image position of every entry. This is the absolute
position 'image-pos', as opposed to 'offset' which is relative to the containing

View file

@ -552,6 +552,7 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
image.SetAllowMissing(allow_missing)
image.SetAllowFakeBlob(allow_fake_blobs)
image.GetEntryContents()
image.drop_absent()
image.GetEntryOffsets()
# We need to pack the entries to figure out where everything
@ -593,12 +594,14 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
image.BuildImage()
if write_map:
image.WriteMap()
missing_list = []
image.CheckMissing(missing_list)
if missing_list:
tout.warning("Image '%s' is missing external blobs and is non-functional: %s" %
(image.name, ' '.join([e.name for e in missing_list])))
_ShowHelpForMissingBlobs(missing_list)
faked_list = []
image.CheckFakedBlobs(faked_list)
if faked_list:
@ -606,6 +609,15 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
"Image '%s' has faked external blobs and is non-functional: %s" %
(image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
for e in faked_list])))
optional_list = []
image.CheckOptional(optional_list)
if optional_list:
tout.warning(
"Image '%s' is missing external blobs but is still functional: %s" %
(image.name, ' '.join([e.name for e in optional_list])))
_ShowHelpForMissingBlobs(optional_list)
missing_bintool_list = []
image.check_missing_bintools(missing_bintool_list)
if missing_bintool_list:

View file

@ -210,7 +210,31 @@ def GetPackString(sym, msg):
raise ValueError('%s has size %d: only 4 and 8 are supported' %
(msg, sym.size))
def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
def GetSymbolOffset(elf_fname, sym_name, base_sym=None):
"""Read the offset of a symbol compared to base symbol
This is useful for obtaining the value of a single symbol relative to the
base of a binary blob.
Args:
elf_fname: Filename of the ELF file to read
sym_name (str): Name of symbol to read
base_sym (str): Base symbol to sue to calculate the offset (or None to
use '__image_copy_start'
Returns:
int: Offset of the symbol relative to the base symbol
"""
if not base_sym:
base_sym = '__image_copy_start'
fname = tools.get_input_filename(elf_fname)
syms = GetSymbols(fname, [base_sym, sym_name])
base = syms[base_sym].address
val = syms[sym_name].address
return val - base
def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
base_sym=None):
"""Replace all symbols in an entry with their correct values
The entry contents is updated so that values for referenced symbols will be
@ -223,7 +247,10 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
entry
entry: Entry to process
section: Section which can be used to lookup symbol values
base_sym: Base symbol marking the start of the image
"""
if not base_sym:
base_sym = '__image_copy_start'
fname = tools.get_input_filename(elf_fname)
syms = GetSymbols(fname, ['image', 'binman'])
if is_elf:
@ -243,7 +270,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
if not syms:
tout.debug('LookupAndWriteSymbols: no syms')
return
base = syms.get('__image_copy_start')
base = syms.get(base_sym)
if not base and not is_elf:
tout.debug('LookupAndWriteSymbols: no base')
return
@ -518,3 +545,18 @@ def read_loadable_segments(data):
rend = start + segment['p_filesz']
segments.append((i, segment['p_paddr'], data[start:rend]))
return segments, entry
def is_valid(data):
"""Check if some binary data is a valid ELF file
Args:
data (bytes): Bytes to check
Returns:
bool: True if a valid Elf file, False if not
"""
try:
DecodeElf(data, 0)
return True
except ELFError:
return False

View file

@ -348,6 +348,16 @@ class TestElf(unittest.TestCase):
finally:
elf.ELF_TOOLS = old_val
def test_is_valid(self):
"""Test is_valid()"""
self.assertEqual(False, elf.is_valid(b''))
self.assertEqual(False, elf.is_valid(b'1234'))
fname = self.ElfTestFile('elf_sections')
data = tools.read_file(fname)
self.assertEqual(True, elf.is_valid(data))
self.assertEqual(False, elf.is_valid(data[4:]))
if __name__ == '__main__':
unittest.main()

View file

@ -216,9 +216,9 @@ This is a blob containing a device tree. The contents of the blob are
obtained from the list of available device-tree files, managed by the
'state' module.
Additional Properties / Entry arguments:
- prepend: Header type to use:
length: 32-bit length header
Additional attributes:
prepend: Header used (e.g. 'length')
.. _etype_blob_ext:
@ -1178,11 +1178,13 @@ Properties / Entry arguments:
- multiple-data-files: boolean to tell binman to pass all files as
datafiles to mkimage instead of creating a temporary file the result
of datafiles concatenation
- filename: filename of output binary generated by mkimage
The data passed to mkimage via the -d flag is collected from subnodes of the
mkimage node, e.g.::
mkimage {
filename = "imximage.bin";
args = "-n test -T imximage";
u-boot-spl {
@ -1190,13 +1192,14 @@ mkimage node, e.g.::
};
This calls mkimage to create an imximage with `u-boot-spl.bin` as the data
file, which mkimage being called like this::
file, with mkimage being called like this::
mkimage -d <data_file> -n test -T imximage <output_file>
The output from mkimage then becomes part of the image produced by
binman. If you need to put mulitple things in the data file, you can use
a section, or just multiple subnodes like this::
binman but also is written into `imximage.bin` file. If you need to put
multiple things in the data file, you can use a section, or just multiple
subnodes like this::
mkimage {
args = "-n test -T imximage";
@ -1208,17 +1211,20 @@ a section, or just multiple subnodes like this::
};
};
Note that binman places the contents (here SPL and TPL) into a single file
and passes that to mkimage using the -d option.
To pass all datafiles untouched to mkimage::
mkimage {
args = "-n rk3399 -T rkspi";
multiple-data-files;
args = "-n rk3399 -T rkspi";
multiple-data-files;
u-boot-tpl {
};
u-boot-tpl {
};
u-boot-spl {
};
u-boot-spl {
};
};
This calls mkimage to create a Rockchip RK3399-specific first stage
@ -1242,17 +1248,17 @@ the 'data-to-imagename' property::
mkimage {
args = "-T imximage";
data-to-imagename';
data-to-imagename;
u-boot-spl {
};
};
That will pass the data to mkimage both as the data file (with -d) and as
the image name (with -n).
the image name (with -n). In both cases, a filename is passed as the
argument, with the actual data being in that file.
If need to pass different data in with -n, then use an imagename subnode::
If need to pass different data in with -n, then use an `imagename` subnode::
mkimage {
args = "-T imximage";
@ -1271,6 +1277,20 @@ This will pass in u-boot-spl as the input data and the .cfgout file as the
-n data.
.. _etype_null:
Entry: null: An entry which has no contents of its own
------------------------------------------------------
Note that the size property must be set since otherwise this entry does not
know how large it should be.
The contents are set by the containing section, e.g. the section's pad
byte.
.. _etype_opensbi:
Entry: opensbi: RISC-V OpenSBI fw_dynamic blob
@ -1478,6 +1498,10 @@ skip-at-start
be written at offset 4 in the image file, since the first 16 bytes are
skipped when writing.
filename
filename to write the unpadded section contents to within the output
directory (None to skip this).
Since a section is also an entry, it inherits all the properies of entries
too.
@ -1497,12 +1521,47 @@ Entry: tee-os: Entry containing an OP-TEE Trusted OS (TEE) blob
Properties / Entry arguments:
- tee-os-path: Filename of file to read into entry. This is typically
called tee-pager.bin
called tee.bin or tee.elf
This entry holds the run-time firmware, typically started by U-Boot SPL.
See the U-Boot README for your architecture or board for how to use it. See
https://github.com/OP-TEE/optee_os for more information about OP-TEE.
Note that if the file is in ELF format, it must go in a FIT. In that case,
this entry will mark itself as absent, providing the data only through the
read_elf_segments() method.
Marking this entry as absent means that it if is used in the wrong context
it can be automatically dropped. Thus it is possible to add an OP-TEE entry
like this::
binman {
tee-os {
};
};
and pass either an ELF or plain binary in with -a tee-os-path <filename>
and have binman do the right thing:
- include the entry if tee.bin is provided and it does NOT have the v1
header
- drop it otherwise
When used within a FIT, we can do::
binman {
fit {
tee-os {
};
};
};
which will split the ELF into separate nodes for each segment, if an ELF
file is provided (see :ref:`etype_fit`), or produce a single node if the
OP-TEE binary v1 format is provided (see optee_doc_) .
.. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary
.. _etype_text:
@ -1567,11 +1626,7 @@ This is the U-Boot binary, containing relocation information to allow it
to relocate itself at runtime. The binary typically includes a device tree
blob at the end of it.
U-Boot can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (fdt)'
in the binman README for more information.
U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
Note that this entry is automatically replaced with u-boot-expanded unless
--no-expanded is used or the node has a 'no-expanded' property.
@ -1701,9 +1756,7 @@ not relocatable so must be loaded to the correct address in SRAM, or written
to run from the correct address if direct flash execution is possible (e.g.
on x86 devices).
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@ -1806,9 +1859,7 @@ entry after this one, or use a u-boot-spl entry instead' which normally
expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
u-boot-spl-dtb
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@ -1844,9 +1895,7 @@ loader. Note that SPL is not relocatable so must be loaded to the correct
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@ -1961,9 +2010,7 @@ entry after this one, or use a u-boot-tpl entry instead, which normally
expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
u-boot-tpl-dtb
TPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@ -2034,6 +2081,128 @@ Entry types that have a part to play in handling microcode:
.. _etype_u_boot_vpl:
Entry: u-boot-vpl: U-Boot VPL binary
------------------------------------
Properties / Entry arguments:
- filename: Filename of u-boot-vpl.bin (default 'vpl/u-boot-vpl.bin')
This is the U-Boot VPL (Verifying Program Loader) binary. This is a small
binary which loads before SPL, typically into on-chip SRAM. It is
responsible for locating, loading and jumping to SPL, the next-stage
loader. Note that VPL is not relocatable so must be loaded to the correct
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
binman uses that to look up symbols to write into the VPL binary.
.. _etype_u_boot_vpl_bss_pad:
Entry: u-boot-vpl-bss-pad: U-Boot VPL binary padded with a BSS region
---------------------------------------------------------------------
Properties / Entry arguments:
None
This holds the padding added after the VPL binary to cover the BSS (Block
Started by Symbol) region. This region holds the various variables used by
VPL. It is set to 0 by VPL when it starts up. If you want to append data to
the VPL image (such as a device tree file), you must pad out the BSS region
to avoid the data overlapping with U-Boot variables. This entry is useful in
that case. It automatically pads out the entry size to cover both the code,
data and BSS.
The contents of this entry will a certain number of zero bytes, determined
by __bss_size
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
binman uses that to look up the BSS address.
.. _etype_u_boot_vpl_dtb:
Entry: u-boot-vpl-dtb: U-Boot VPL device tree
---------------------------------------------
Properties / Entry arguments:
- filename: Filename of u-boot.dtb (default 'vpl/u-boot-vpl.dtb')
This is the VPL device tree, containing configuration information for
VPL. VPL needs this to know what devices are present and which drivers
to activate.
.. _etype_u_boot_vpl_elf:
Entry: u-boot-vpl-elf: U-Boot VPL ELF image
-------------------------------------------
Properties / Entry arguments:
- filename: Filename of VPL u-boot (default 'vpl/u-boot-vpl')
This is the U-Boot VPL ELF image. It does not include a device tree but can
be relocated to any address for execution.
.. _etype_u_boot_vpl_expanded:
Entry: u-boot-vpl-expanded: U-Boot VPL flat binary broken out into its component parts
--------------------------------------------------------------------------------------
Properties / Entry arguments:
- vpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
select)
This is a section containing the U-Boot binary, BSS padding if needed and a
devicetree. Using this entry type automatically creates this section, with
the following entries in it:
u-boot-vpl-nodtb
u-boot-vpl-bss-pad
u-boot-dtb
Having the devicetree separate allows binman to update it in the final
image, so that the entries positions are provided to the running U-Boot.
This entry is selected based on the value of the 'vpl-dtb' entryarg. If
this is non-empty (and not 'n' or '0') then this expanded entry is selected.
.. _etype_u_boot_vpl_nodtb:
Entry: u-boot-vpl-nodtb: VPL binary without device tree appended
----------------------------------------------------------------
Properties / Entry arguments:
- filename: Filename to include (default 'vpl/u-boot-vpl-nodtb.bin')
This is the U-Boot VPL binary, It does not include a device tree blob at
the end of it so may not be able to work without it, assuming VPL needs
a device tree to operate on your platform. You can add a u_boot_vpl_dtb
entry after this one, or use a u_boot_vpl entry instead, which normally
expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
u-boot-vpl-dtb
VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
binman uses that to look up symbols to write into the VPL binary.
.. _etype_u_boot_with_ucode_ptr:
Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer

View file

@ -73,7 +73,9 @@ class Entry(object):
compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
orig_offset: Original offset value read from node
orig_size: Original size value read from node
missing: True if this entry is missing its contents
missing: True if this entry is missing its contents. Note that if it is
optional, this entry will not appear in the list generated by
entry.CheckMissing() since it is considered OK for it to be missing.
allow_missing: Allow children of this entry to be missing (used by
subclasses such as Entry_section)
allow_fake: Allow creating a dummy fake file if the blob file is not
@ -91,6 +93,12 @@ class Entry(object):
file, or is a binary file produced from an ELF file
auto_write_symbols (bool): True to write ELF symbols into this entry's
contents
absent (bool): True if this entry is absent. This can be controlled by
the entry itself, allowing it to vanish in certain circumstances.
An absent entry is removed during processing so that it does not
appear in the map
optional (bool): True if this entry contains an optional external blob
overlap (bool): True if this entry overlaps with others
"""
fake_dir = None
@ -133,6 +141,11 @@ class Entry(object):
self.comp_bintool = None
self.elf_fname = None
self.auto_write_symbols = auto_write_symbols
self.absent = False
self.optional = False
self.overlap = False
self.elf_base_sym = None
self.offset_from_elf = None
@staticmethod
def FindEntryClass(etype, expanded):
@ -284,9 +297,15 @@ class Entry(object):
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
self.extend_size = fdt_util.GetBool(self._node, 'extend-size')
self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
self.optional = fdt_util.GetBool(self._node, 'optional')
self.overlap = fdt_util.GetBool(self._node, 'overlap')
if self.overlap:
self.required_props += ['offset', 'size']
# This is only supported by blobs and sections at present
self.compress = fdt_util.GetString(self._node, 'compress', 'none')
self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node,
'offset-from-elf')
def GetDefaultFilename(self):
return None
@ -444,7 +463,7 @@ class Entry(object):
Returns:
True if the contents were found, False if another call is needed
after the other entries are processed.
after the other entries are processed, None if there is no contents
"""
# No contents by default: subclasses can implement this
return True
@ -483,7 +502,10 @@ class Entry(object):
if self.offset_unset:
self.Raise('No offset set with offset-unset: should another '
'entry provide this correct offset?')
self.offset = tools.align(offset, self.align)
elif self.offset_from_elf:
self.offset = self.lookup_offset()
else:
self.offset = tools.align(offset, self.align)
needed = self.pad_before + self.contents_size + self.pad_after
needed = tools.align(needed, self.align_size)
size = self.size
@ -572,7 +594,9 @@ class Entry(object):
Returns:
bytes content of the entry, excluding any padding. If the entry is
compressed, the compressed data is returned
compressed, the compressed data is returned. If the entry data
is not yet available, False can be returned. If the entry data
is null, then None is returned.
"""
self.Detail('GetData: size %s' % to_hex_size(self.data))
return self.data
@ -659,7 +683,7 @@ class Entry(object):
# Check if we are writing symbols into an ELF file
is_elf = self.GetDefaultFilename() == self.elf_fname
elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(),
is_elf)
is_elf, self.elf_base_sym)
def CheckEntries(self):
"""Check that the entry offsets are correct
@ -1034,14 +1058,15 @@ features to produce new behaviours.
self.allow_fake = allow_fake
def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs
"""Check if the entry has missing external blobs
If there are missing blobs, the entries are added to the list
If there are missing (non-optional) blobs, the entries are added to the
list
Args:
missing_list: List of Entry objects to be added to
"""
if self.missing:
if self.missing and not self.optional:
missing_list.append(self)
def check_fake_fname(self, fname, size=0):
@ -1080,6 +1105,17 @@ features to produce new behaviours.
# This is meaningless for anything other than blobs
pass
def CheckOptional(self, optional_list):
"""Check if the entry has missing but optional external blobs
If there are missing (optional) blobs, the entries are added to the list
Args:
optional_list (list): List of Entry objects to be added to
"""
if self.missing and self.optional:
optional_list.append(self)
def GetAllowMissing(self):
"""Get whether a section allows missing external blobs
@ -1281,3 +1317,31 @@ features to produce new behaviours.
not_present.append(prop)
if not_present:
self.Raise(f"'{self.etype}' entry is missing properties: {' '.join(not_present)}")
def mark_absent(self, msg):
tout.info("Entry '%s' marked absent: %s" % (self._node.path, msg))
self.absent = True
def read_elf_segments(self):
"""Read segments from an entry that can generate an ELF file
Returns:
tuple:
list of segments, each:
int: Segment number (0 = first)
int: Start address of segment in memory
bytes: Contents of segment
int: entry address of ELF file
"""
return None
def lookup_offset(self):
node, sym_name, offset = self.offset_from_elf
entry = self.section.FindEntryByNode(node)
if not entry:
self.Raise("Cannot find entry for node '%s'" % node.name)
if not entry.elf_fname:
entry.Raise("Need elf-fname property '%s'" % node.name)
val = elf.GetSymbolOffset(entry.elf_fname, sym_name,
entry.elf_base_sym)
return val + offset

View file

@ -63,6 +63,7 @@ class Entry__testing(Entry):
'bad-update-contents-twice')
self.return_contents_later = fdt_util.GetBool(self._node,
'return-contents-later')
self.set_to_absent = fdt_util.GetBool(self._node, 'set-to-absent')
# Set to True when the entry is ready to process the FDT.
self.process_fdt_ready = False
@ -119,6 +120,8 @@ class Entry__testing(Entry):
if self.require_bintool_for_contents:
if self.bintool_for_contents is None:
self.Raise("Required bintool unusable in ObtainContents()")
if self.set_to_absent:
self.mark_absent('for testing purposes')
return True
def GetOffsets(self):

View file

@ -35,11 +35,17 @@ class Entry_blob(Entry):
super().__init__(section, etype, node,
auto_write_symbols=auto_write_symbols)
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
self.elf_fname = fdt_util.GetString(self._node, 'elf-filename',
self.elf_fname)
self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym')
if not self.auto_write_symbols:
if fdt_util.GetBool(self._node, 'write-symbols'):
self.auto_write_symbols = True
def ObtainContents(self, fake_size=0):
self._filename = self.GetDefaultFilename()
self._pathname = tools.get_input_filename(self._filename,
self.external and self.section.GetAllowMissing())
self.external and (self.optional or self.section.GetAllowMissing()))
# Allow the file to be missing
if not self._pathname:
self._pathname, faked = self.check_fake_fname(self._filename,

View file

@ -392,8 +392,8 @@ class Entry_fit(Entry_section):
_add_entries(self._node, 0, self._node)
# Keep a copy of all entries, including generator entries, since these
# removed from self._entries later.
# Keep a copy of all entries, including generator entries, since those
# are removed from self._entries later.
self._priv_entries = dict(self._entries)
def BuildSectionData(self, required):
@ -540,50 +540,50 @@ class Entry_fit(Entry_section):
else:
self.Raise("Generator node requires 'fit,fdt-list' property")
def _gen_split_elf(base_node, node, elf_data, missing):
def _gen_split_elf(base_node, node, segments, entry_addr):
"""Add nodes for the ELF file, one per group of contiguous segments
Args:
base_node (Node): Template node from the binman definition
node (Node): Node to replace (in the FIT being built)
data (bytes): ELF-format data to process (may be empty)
missing (bool): True if any of the data is missing
segments (list): list of segments, each:
int: Segment number (0 = first)
int: Start address of segment in memory
bytes: Contents of segment
entry_addr (int): entry address of ELF file
"""
# If any pieces are missing, skip this. The missing entries will
# show an error
if not missing:
try:
segments, entry = elf.read_loadable_segments(elf_data)
except ValueError as exc:
self._raise_subnode(node,
f'Failed to read ELF file: {str(exc)}')
for (seq, start, data) in segments:
node_name = node.name[1:].replace('SEQ', str(seq + 1))
with fsw.add_node(node_name):
loadables.append(node_name)
for pname, prop in node.props.items():
if not pname.startswith('fit,'):
fsw.property(pname, prop.bytes)
elif pname == 'fit,load':
fsw.property_u32('load', start)
elif pname == 'fit,entry':
if seq == 0:
fsw.property_u32('entry', entry)
elif pname == 'fit,data':
fsw.property('data', bytes(data))
elif pname != 'fit,operation':
self._raise_subnode(
node, f"Unknown directive '{pname}'")
for (seq, start, data) in segments:
node_name = node.name[1:].replace('SEQ', str(seq + 1))
with fsw.add_node(node_name):
loadables.append(node_name)
for pname, prop in node.props.items():
if not pname.startswith('fit,'):
fsw.property(pname, prop.bytes)
elif pname == 'fit,load':
fsw.property_u32('load', start)
elif pname == 'fit,entry':
if seq == 0:
fsw.property_u32('entry', entry_addr)
elif pname == 'fit,data':
fsw.property('data', bytes(data))
elif pname != 'fit,operation':
self._raise_subnode(
node, f"Unknown directive '{pname}'")
def _gen_node(base_node, node, depth, in_images, entry):
"""Generate nodes from a template
This creates one node for each member of self._fdts using the
provided template. If a property value contains 'NAME' it is
replaced with the filename of the FDT. If a property value contains
SEQ it is replaced with the node sequence number, where 1 is the
first.
This creates one or more nodes depending on the fit,operation being
used.
For OP_GEN_FDT_NODES it creates one node for each member of
self._fdts using the provided template. If a property value contains
'NAME' it is replaced with the filename of the FDT. If a property
value contains SEQ it is replaced with the node sequence number,
where 1 is the first.
For OP_SPLIT_ELF it emits one node for each section in the ELF file.
If the file is missing, nothing is generated.
Args:
base_node (Node): Base Node of the FIT (with 'description'
@ -592,6 +592,8 @@ class Entry_fit(Entry_section):
depth (int): Current node depth (0 is the base 'fit' node)
in_images (bool): True if this is inside the 'images' node, so
that 'data' properties should be generated
entry (entry_Section): Entry for the section containing the
contents of this node
"""
oper = self._get_operation(base_node, node)
if oper == OP_GEN_FDT_NODES:
@ -600,13 +602,28 @@ class Entry_fit(Entry_section):
# Entry_section.ObtainContents() either returns True or
# raises an exception.
data = None
missing_list = []
missing_opt_list = []
entry.ObtainContents()
entry.Pack(0)
data = entry.GetData()
entry.CheckMissing(missing_list)
entry.CheckMissing(missing_opt_list)
entry.CheckOptional(missing_opt_list)
_gen_split_elf(base_node, node, data, bool(missing_list))
# If any pieces are missing, skip this. The missing entries will
# show an error
if not missing_opt_list:
segs = entry.read_elf_segments()
if segs:
segments, entry_addr = segs
else:
elf_data = entry.GetData()
try:
segments, entry_addr = (
elf.read_loadable_segments(elf_data))
except ValueError as exc:
self._raise_subnode(
node, f'Failed to read ELF file: {str(exc)}')
_gen_split_elf(base_node, node, segments, entry_addr)
def _add_node(base_node, depth, node):
"""Add nodes to the output FIT
@ -638,8 +655,7 @@ class Entry_fit(Entry_section):
for subnode in node.subnodes:
subnode_path = f'{rel_path}/{subnode.name}'
if has_images and not (subnode.name.startswith('hash') or
subnode.name.startswith('signature')):
if has_images and not self.IsSpecialSubnode(subnode):
# This subnode is a content node not meant to appear in
# the FIT (e.g. "/images/kernel/u-boot"), so don't call
# fsw.add_node() or _add_node() for it.

View file

@ -57,24 +57,24 @@ class Entry_mkimage(Entry):
Note that binman places the contents (here SPL and TPL) into a single file
and passes that to mkimage using the -d option.
To pass all datafiles untouched to mkimage::
To pass all datafiles untouched to mkimage::
mkimage {
args = "-n rk3399 -T rkspi";
multiple-data-files;
mkimage {
args = "-n rk3399 -T rkspi";
multiple-data-files;
u-boot-tpl {
};
u-boot-tpl {
};
u-boot-spl {
};
};
u-boot-spl {
};
};
This calls mkimage to create a Rockchip RK3399-specific first stage
bootloader, made of TPL+SPL. Since this first stage bootloader requires to
align the TPL and SPL but also some weird hacks that is handled by mkimage
directly, binman is told to not perform the concatenation of datafiles prior
to passing the data to mkimage.
This calls mkimage to create a Rockchip RK3399-specific first stage
bootloader, made of TPL+SPL. Since this first stage bootloader requires to
align the TPL and SPL but also some weird hacks that is handled by mkimage
directly, binman is told to not perform the concatenation of datafiles prior
to passing the data to mkimage.
To use CONFIG options in the arguments, use a string list instead, as in
this example which also produces four arguments::

View file

@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright 2023 Google LLC
# Written by Simon Glass <sjg@chromium.org>
#
from binman.entry import Entry
from dtoc import fdt_util
from patman import tools
class Entry_null(Entry):
"""An entry which has no contents of its own
Note that the size property must be set since otherwise this entry does not
know how large it should be.
The contents are set by the containing section, e.g. the section's pad
byte.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.required_props = ['size']
def ObtainContents(self):
# null contents
return None

View file

@ -144,6 +144,10 @@ class Entry_section(Entry):
be written at offset 4 in the image file, since the first 16 bytes are
skipped when writing.
filename
filename to write the unpadded section contents to within the output
directory (None to skip this).
Since a section is also an entry, it inherits all the properies of entries
too.
@ -163,6 +167,18 @@ class Entry_section(Entry):
self._skip_at_start = None
self._end_4gb = False
self._ignore_missing = False
self._filename = None
def IsSpecialSubnode(self, node):
"""Check if a node is a special one used by the section itself
Some notes are used for hashing / signatures and do not add entries to
the actual section.
Returns:
bool: True if the node is a special one, else False
"""
return node.name.startswith('hash') or node.name.startswith('signature')
def ReadNode(self):
"""Read properties from the section node"""
@ -183,12 +199,14 @@ class Entry_section(Entry):
self._skip_at_start = 0
self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
self.align_default = fdt_util.GetInt(self._node, 'align-default', 0)
self._filename = fdt_util.GetString(self._node, 'filename',
self._filename)
self.ReadEntries()
def ReadEntries(self):
for node in self._node.subnodes:
if node.name.startswith('hash') or node.name.startswith('signature'):
if self.IsSpecialSubnode(node):
continue
entry = Entry.Create(self, node,
expanded=self.GetImage().use_expanded,
@ -258,6 +276,7 @@ class Entry_section(Entry):
Args:
entry: Entry to check
entry_data: Data for the entry, False if is null
Returns:
Contents of the entry along with any pad bytes before and
@ -312,14 +331,32 @@ class Entry_section(Entry):
# earlier in the image description. See testCollectionSection().
if not required and entry_data is None:
return None
data = self.GetPaddedDataForEntry(entry, entry_data)
entry_data_final = entry_data
if entry_data is None:
pad_byte = (entry._pad_byte if isinstance(entry, Entry_section)
else self._pad_byte)
entry_data_final = tools.get_bytes(self._pad_byte, entry.size)
data = self.GetPaddedDataForEntry(entry, entry_data_final)
# Handle empty space before the entry
pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
if pad > 0:
section_data += tools.get_bytes(self._pad_byte, pad)
# Add in the actual entry data
section_data += data
if entry.overlap:
end_offset = entry.offset + entry.size
if end_offset > len(section_data):
entry.Raise("Offset %#x (%d) ending at %#x (%d) must overlap with existing entries" %
(entry.offset, entry.offset, end_offset,
end_offset))
# Don't write anything for null entries'
if entry_data is not None:
section_data = (section_data[:entry.offset] + data +
section_data[entry.offset + entry.size:])
else:
section_data += data
self.Detail('GetData: %d entries, total size %#x' %
(len(self._entries), len(section_data)))
@ -348,7 +385,8 @@ class Entry_section(Entry):
"""Get the contents of an entry
This builds the contents of the section, stores this as the contents of
the section and returns it
the section and returns it. If the section has a filename, the data is
written there also.
Args:
required: True if the data must be present, False if it is OK to
@ -363,6 +401,8 @@ class Entry_section(Entry):
if data is None:
return None
self.SetContents(data)
if self._filename:
tools.write_file(tools.get_output_filename(self._filename), data)
return data
def GetOffsets(self):
@ -439,12 +479,13 @@ class Entry_section(Entry):
(entry.offset, entry.offset, entry.size, entry.size,
self._node.path, self._skip_at_start,
self._skip_at_start, max_size, max_size))
if entry.offset < offset and entry.size:
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
"ending at %#x (%d)" %
(entry.offset, entry.offset, prev_name, offset, offset))
offset = entry.offset + entry.size
prev_name = entry.GetPath()
if not entry.overlap:
if entry.offset < offset and entry.size:
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' ending at %#x (%d)" %
(entry.offset, entry.offset, prev_name, offset,
offset))
offset = entry.offset + entry.size
prev_name = entry.GetPath()
def WriteSymbols(self, section):
"""Write symbol values into binary files for access at run time"""
@ -662,10 +703,13 @@ class Entry_section(Entry):
def GetEntryContents(self, skip_entry=None):
"""Call ObtainContents() for each entry in the section
Note that this may set entry.absent to True if the entry is not
actually needed
"""
def _CheckDone(entry):
if entry != skip_entry:
if not entry.ObtainContents():
if entry.ObtainContents() is False:
next_todo.append(entry)
return entry
@ -706,6 +750,10 @@ class Entry_section(Entry):
todo)
return True
def drop_absent(self):
"""Drop entries which are absent"""
self._entries = {n: e for n, e in self._entries.items() if not e.absent}
def _SetEntryOffsetSize(self, name, offset, size):
"""Set the offset and size of an entry
@ -846,7 +894,8 @@ class Entry_section(Entry):
def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs
If there are missing blobs, the entries are added to the list
If there are missing (non-optional) blobs, the entries are added to the
list
Args:
missing_list: List of Entry objects to be added to
@ -865,6 +914,17 @@ class Entry_section(Entry):
for entry in self._entries.values():
entry.CheckFakedBlobs(faked_blobs_list)
def CheckOptional(self, optional_list):
"""Check the section for missing but optional external blobs
If there are missing (optional) blobs, the entries are added to the list
Args:
optional_list (list): List of Entry objects to be added to
"""
for entry in self._entries.values():
entry.CheckOptional(optional_list)
def check_missing_bintools(self, missing_list):
"""Check if any entries in this section have missing bintools
@ -931,3 +991,12 @@ class Entry_section(Entry):
super().AddBintools(btools)
for entry in self._entries.values():
entry.AddBintools(btools)
def read_elf_segments(self):
entries = self.GetEntries()
# If the section only has one entry, see if it can provide ELF segments
if len(entries) == 1:
for entry in entries.values():
return entry.read_elf_segments()
return None

View file

@ -4,19 +4,93 @@
# Entry-type module for OP-TEE Trusted OS firmware blob
#
import struct
from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
from binman import elf
class Entry_tee_os(Entry_blob_named_by_arg):
"""Entry containing an OP-TEE Trusted OS (TEE) blob
Properties / Entry arguments:
- tee-os-path: Filename of file to read into entry. This is typically
called tee-pager.bin
called tee.bin or tee.elf
This entry holds the run-time firmware, typically started by U-Boot SPL.
See the U-Boot README for your architecture or board for how to use it. See
https://github.com/OP-TEE/optee_os for more information about OP-TEE.
Note that if the file is in ELF format, it must go in a FIT. In that case,
this entry will mark itself as absent, providing the data only through the
read_elf_segments() method.
Marking this entry as absent means that it if is used in the wrong context
it can be automatically dropped. Thus it is possible to add an OP-TEE entry
like this::
binman {
tee-os {
};
};
and pass either an ELF or plain binary in with -a tee-os-path <filename>
and have binman do the right thing:
- include the entry if tee.bin is provided and it does NOT have the v1
header
- drop it otherwise
When used within a FIT, we can do::
binman {
fit {
tee-os {
};
};
};
which will split the ELF into separate nodes for each segment, if an ELF
file is provided (see :ref:`etype_fit`), or produce a single node if the
OP-TEE binary v1 format is provided (see optee_doc_) .
.. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node, 'tee-os')
self.external = True
@staticmethod
def is_optee_bin_v1(data):
return len(data) >= 8 and data[0:5] == b'OPTE\x01'
def ObtainContents(self, fake_size=0):
result = super().ObtainContents(fake_size)
if not self.missing:
# If using the flat binary (without the OP-TEE header), then it is
# just included as a blob. But if it is an ELF or usees the v1
# binary header, then the FIT implementation will call
# read_elf_segments() to get the segment information
if elf.is_valid(self.data):
self.mark_absent('uses Elf format which must be in a FIT')
elif self.is_optee_bin_v1(self.data):
# The FIT implementation will call read_elf_segments() to get
# the segment information
self.mark_absent('uses v1 format which must be in a FIT')
return result
def read_elf_segments(self):
data = self.GetData()
if self.is_optee_bin_v1(data):
# OP-TEE v1 format (tee.bin)
init_sz, start_hi, start_lo, _, paged_sz = (
struct.unpack_from('<5I', data, 0x8))
if paged_sz != 0:
self.Raise("OP-TEE paged mode not supported")
e_entry = (start_hi << 32) + start_lo
p_addr = e_entry
p_data = data[0x1c:]
if len(p_data) != init_sz:
self.Raise("Invalid OP-TEE file: size mismatch (expected %#x, have %#x)" %
(init_sz, len(p_data)))
return [[0, p_addr, p_data]], e_entry
return None

View file

@ -18,11 +18,7 @@ class Entry_u_boot(Entry_blob):
to relocate itself at runtime. The binary typically includes a device tree
blob at the end of it.
U-Boot can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (fdt)'
in the binman README for more information.
U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
Note that this entry is automatically replaced with u-boot-expanded unless
--no-expanded is used or the node has a 'no-expanded' property.

View file

@ -21,9 +21,7 @@ class Entry_u_boot_spl(Entry_blob):
to run from the correct address if direct flash execution is possible (e.g.
on x86 devices).
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@ -36,7 +34,6 @@ class Entry_u_boot_spl(Entry_blob):
def __init__(self, section, etype, node):
super().__init__(section, etype, node, auto_write_symbols=True)
self.elf_fname = 'spl/u-boot-spl'
self.auto_write_symbols = True
def GetDefaultFilename(self):
return 'spl/u-boot-spl.bin'

View file

@ -21,9 +21,7 @@ class Entry_u_boot_spl_nodtb(Entry_blob):
expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
u-boot-spl-dtb
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.

View file

@ -21,9 +21,7 @@ class Entry_u_boot_tpl(Entry_blob):
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.

View file

@ -21,9 +21,7 @@ class Entry_u_boot_tpl_nodtb(Entry_blob):
expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
u-boot-tpl-dtb
TPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.

View file

@ -21,9 +21,7 @@ class Entry_u_boot_vpl(Entry_blob):
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
SPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.

View file

@ -21,11 +21,7 @@ class Entry_u_boot_vpl_nodtb(Entry_blob):
expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
u-boot-vpl-dtb
VPL can access binman symbols at runtime. See:
'Access to binman entry offsets at run time (symbols)'
in the binman README for more information.
VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
binman uses that to look up symbols to write into the VPL binary.

View file

@ -112,6 +112,8 @@ REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
# Supported compression bintools
COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
TEE_ADDR = 0x5678
class TestFunctional(unittest.TestCase):
"""Functional tests for binman
@ -219,6 +221,9 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('tee.elf',
tools.read_file(cls.ElfTestFile('elf_sections')))
# Newer OP_TEE file in v1 binary format
cls.make_tee_bin('tee.bin')
cls.comp_bintools = {}
for name in COMP_BINTOOLS:
cls.comp_bintools[name] = bintool.Bintool.create(name)
@ -644,6 +649,14 @@ class TestFunctional(unittest.TestCase):
def ElfTestFile(cls, fname):
return os.path.join(cls._elf_testdir, fname)
@classmethod
def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
dummy, paged_sz) + U_BOOT_DATA
data += extra_data
TestFunctional._MakeInputFile(fname, data)
def AssertInList(self, grep_list, target):
"""Assert that at least one of a list of things is in a target
@ -6077,5 +6090,225 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
'Cannot write symbols to an ELF file without Python elftools',
str(exc.exception))
def testSectionFilename(self):
"""Check writing of section contents to a file"""
data = self._DoReadFile('261_section_fname.dts')
expected = (b'&&' + U_BOOT_DATA + b'&&&' +
tools.get_bytes(ord('!'), 7) +
U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
self.assertEqual(expected, data)
sect_fname = tools.get_output_filename('outfile.bin')
self.assertTrue(os.path.exists(sect_fname))
sect_data = tools.read_file(sect_fname)
self.assertEqual(U_BOOT_DATA, sect_data)
def testAbsent(self):
"""Check handling of absent entries"""
data = self._DoReadFile('262_absent.dts')
self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
def testPackTeeOsOptional(self):
"""Test that an image with an optional TEE binary can be created"""
entry_args = {
'tee-os-path': 'tee.elf',
}
data = self._DoReadFileDtb('263_tee_os_opt.dts',
entry_args=entry_args)[0]
self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
def checkFitTee(self, dts, tee_fname):
"""Check that a tee-os entry works and returns data
Args:
dts (str): Device tree filename to use
tee_fname (str): filename containing tee-os
Returns:
bytes: Image contents
"""
if not elf.ELF_TOOLS:
self.skipTest('Python elftools not available')
entry_args = {
'of-list': 'test-fdt1 test-fdt2',
'default-dt': 'test-fdt2',
'tee-os-path': tee_fname,
}
test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
data = self._DoReadFileDtb(dts, entry_args=entry_args,
extra_indirs=[test_subdir])[0]
return data
def testFitTeeOsOptionalFit(self):
"""Test an image with a FIT with an optional OP-TEE binary"""
data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
# There should be only one node, holding the data set up in SetUpClass()
# for tee.bin
dtb = fdt.Fdt.FromData(data)
dtb.Scan()
node = dtb.GetNode('/images/tee-1')
self.assertEqual(TEE_ADDR,
fdt_util.fdt32_to_cpu(node.props['load'].value))
self.assertEqual(TEE_ADDR,
fdt_util.fdt32_to_cpu(node.props['entry'].value))
self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
def testFitTeeOsOptionalFitBad(self):
"""Test an image with a FIT with an optional OP-TEE binary"""
with self.assertRaises(ValueError) as exc:
self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
self.assertIn(
"Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
str(exc.exception))
def testFitTeeOsBad(self):
"""Test an OP-TEE binary with wrong formats"""
self.make_tee_bin('tee.bad1', 123)
with self.assertRaises(ValueError) as exc:
self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
self.assertIn(
"Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
str(exc.exception))
self.make_tee_bin('tee.bad2', 0, b'extra data')
with self.assertRaises(ValueError) as exc:
self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
self.assertIn(
"Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
str(exc.exception))
def testExtblobOptional(self):
"""Test an image with an external blob that is optional"""
with test_util.capture_sys_output() as (stdout, stderr):
data = self._DoReadFile('266_blob_ext_opt.dts')
self.assertEqual(REFCODE_DATA, data)
err = stderr.getvalue()
self.assertRegex(
err,
"Image '.*' is missing external blobs but is still functional: missing")
def testSectionInner(self):
"""Test an inner section with a size"""
data = self._DoReadFile('267_section_inner.dts')
expected = U_BOOT_DATA + tools.get_bytes(0, 12)
self.assertEqual(expected, data)
def testNull(self):
"""Test an image with a null entry"""
data = self._DoReadFile('268_null.dts')
self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
def testOverlap(self):
"""Test an image with a overlapping entry"""
data = self._DoReadFile('269_overlap.dts')
self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
image = control.images['image']
entries = image.GetEntries()
self.assertIn('inset', entries)
inset = entries['inset']
self.assertEqual(1, inset.offset);
self.assertEqual(1, inset.image_pos);
self.assertEqual(2, inset.size);
def testOverlapNull(self):
"""Test an image with a null overlap"""
data = self._DoReadFile('270_overlap_null.dts')
self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
# Check the FMAP
fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
self.assertEqual(4, fhdr.nareas)
fiter = iter(fentries)
fentry = next(fiter)
self.assertEqual(b'SECTION', fentry.name)
self.assertEqual(0, fentry.offset)
self.assertEqual(len(U_BOOT_DATA), fentry.size)
self.assertEqual(0, fentry.flags)
fentry = next(fiter)
self.assertEqual(b'U_BOOT', fentry.name)
self.assertEqual(0, fentry.offset)
self.assertEqual(len(U_BOOT_DATA), fentry.size)
self.assertEqual(0, fentry.flags)
# Make sure that the NULL entry appears in the FMAP
fentry = next(fiter)
self.assertEqual(b'NULL', fentry.name)
self.assertEqual(1, fentry.offset)
self.assertEqual(2, fentry.size)
self.assertEqual(0, fentry.flags)
fentry = next(fiter)
self.assertEqual(b'FMAP', fentry.name)
self.assertEqual(len(U_BOOT_DATA), fentry.offset)
def testOverlapBad(self):
"""Test an image with a bad overlapping entry"""
with self.assertRaises(ValueError) as exc:
self._DoReadFile('271_overlap_bad.dts')
self.assertIn(
"Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
str(exc.exception))
def testOverlapNoOffset(self):
"""Test an image with a bad overlapping entry"""
with self.assertRaises(ValueError) as exc:
self._DoReadFile('272_overlap_no_size.dts')
self.assertIn(
"Node '/binman/inset': 'fill' entry is missing properties: size",
str(exc.exception))
def testBlobSymbol(self):
"""Test a blob with symbols read from an ELF file"""
elf_fname = self.ElfTestFile('blob_syms')
TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
TestFunctional._MakeInputFile('blob_syms.bin',
tools.read_file(self.ElfTestFile('blob_syms.bin')))
data = self._DoReadFile('273_blob_symbol.dts')
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
self.assertEqual(syms['_binman_sym_magic'].address, addr)
self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
expected = sym_values
self.assertEqual(expected, data[:len(expected)])
def testOffsetFromElf(self):
"""Test a blob with symbols read from an ELF file"""
elf_fname = self.ElfTestFile('blob_syms')
TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
TestFunctional._MakeInputFile('blob_syms.bin',
tools.read_file(self.ElfTestFile('blob_syms.bin')))
data = self._DoReadFile('274_offset_from_elf.dts')
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
image = control.images['image']
entries = image.GetEntries()
self.assertIn('inset', entries)
inset = entries['inset']
self.assertEqual(base + 4, inset.offset);
self.assertEqual(base + 4, inset.image_pos);
self.assertEqual(4, inset.size);
self.assertIn('inset2', entries)
inset = entries['inset2']
self.assertEqual(base + 8, inset.offset);
self.assertEqual(base + 8, inset.image_pos);
self.assertEqual(4, inset.size);
if __name__ == "__main__":
unittest.main()

View file

@ -94,9 +94,6 @@ class Image(section.Entry_section):
def ReadNode(self):
super().ReadNode()
filename = fdt_util.GetString(self._node, 'filename')
if filename:
self._filename = filename
self.allow_repack = fdt_util.GetBool(self._node, 'allow-repack')
self._symlink = fdt_util.GetString(self._node, 'symlink')

View file

@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
pad-byte = <0x26>;
size = <0x20>;
section@0 {
size = <0x10>;
pad-byte = <0x21>;
pad-before = <2>;
pad-after = <3>;
section {
filename = "outfile.bin";
u-boot {
};
};
};
section@1 {
u-boot {
};
};
};
};

View file

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
u-boot {
};
_testing {
set-to-absent;
};
u-boot-img {
};
};
};

View file

@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
u-boot {
};
tee-os {
/*
* this results in nothing being added since only the
* .bin format is supported by this etype, unless it is
* part of a FIT
*/
};
u-boot-img {
};
};
};

View file

@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
fit {
description = "test-desc";
#address-cells = <1>;
fit,fdt-list = "of-list";
images {
@tee-SEQ {
fit,operation = "split-elf";
description = "TEE";
type = "tee";
arch = "arm64";
os = "tee";
compression = "none";
fit,load;
fit,entry;
fit,data;
tee-os {
};
};
};
};
};
};

View file

@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
fit {
description = "test-desc";
#address-cells = <1>;
fit,fdt-list = "of-list";
images {
@tee-SEQ {
fit,operation = "split-elf";
description = "TEE";
type = "tee";
arch = "arm64";
os = "tee";
compression = "none";
fit,load;
fit,entry;
fit,data;
tee-os {
};
/*
* mess up the ELF data by adding
* another bit of data at the end
*/
u-boot {
};
};
};
};
};
};

View file

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
ok {
type = "blob-ext";
filename = "refcode.bin";
};
missing {
type = "blob-ext";
filename = "missing.bin";
optional;
};
};
};

View file

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
section {
size = <0x10>;
u-boot {
};
};
};
};

View file

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
pad-byte = <0xff>;
u-boot {
};
null {
size = <4>;
};
u-boot-img {
};
};
};

View file

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
u-boot {
};
inset {
type = "fill";
fill-byte = [61];
offset = <1>;
size = <2>;
overlap;
};
};
};

View file

@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
section {
u-boot {
};
null {
offset = <1>;
size = <2>;
overlap;
};
};
fmap {
};
};
};

View file

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
u-boot {
};
inset {
type = "fill";
fill-byte = [61];
offset = <0x10>;
size = <2>;
overlap;
};
};
};

View file

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
u-boot {
};
inset {
type = "fill";
fill-byte = [61];
overlap;
};
};
};

View file

@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
blob {
filename = "blob_syms.bin";
write-symbols;
elf-filename = "blob_syms";
elf-base-sym = "__my_start_sym";
};
inset {
type = "null";
offset = <4>;
size = <8>;
overlap;
};
};
};

View file

@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
blob: blob {
filename = "blob_syms.bin";
elf-filename = "blob_syms";
elf-base-sym = "__my_start_sym";
};
inset {
type = "null";
offset-from-elf = <&blob>, "val3", <0>;
size = <4>;
overlap;
};
inset2 {
type = "null";
offset-from-elf = <&blob>, "val3", <4>;
size = <4>;
overlap;
};
};
};

View file

@ -30,11 +30,12 @@ LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds
LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
LDS_EFL_SECTIONS := -T $(SRC)elf_sections.lds
LDS_BLOB := -T $(SRC)blob_syms.lds
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \
u_boot_binman_embed u_boot_binman_embed_sm elf_sections
u_boot_binman_embed u_boot_binman_embed_sm elf_sections blob_syms.bin
all: $(TARGETS)
@ -71,6 +72,12 @@ u_boot_binman_embed: u_boot_binman_embed.c
u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED)
u_boot_binman_embed_sm: u_boot_binman_embed_sm.c
blob_syms.bin: blob_syms
$(OBJCOPY) -O binary $< -R .note.gnu.build-id $@
blob_syms: CFLAGS += $(LDS_BLOB)
blob_syms: blob_syms.c
elf_sections: CFLAGS += $(LDS_EFL_SECTIONS)
elf_sections: elf_sections.c

View file

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2017 Google, Inc
*
* Simple program to create some binman symbols. This is used by binman tests.
*/
typedef unsigned long ulong;
#include <linux/kconfig.h>
#include <binman_sym.h>
DECLARE_BINMAN_MAGIC_SYM;
unsigned long val1 = 123;
unsigned long val2 = 456;
binman_sym_declare(unsigned long, inset, offset);
unsigned long val3 = 789;
unsigned long val4 = 999;
binman_sym_declare(unsigned long, inset, size);

View file

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2016 Google, Inc
*/
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
. = 0x00000010;
_start = .;
. = ALIGN(4);
.text :
{
__my_start_sym = .;
*(.text*)
}
. = ALIGN(4);
.binman_sym_table : {
__binman_sym_start = .;
KEEP(*(SORT(.binman_sym*)));
__binman_sym_end = .;
}
.interp : { *(.interp*) }
}

View file

@ -281,6 +281,34 @@ def GetPhandleList(node, propname):
value = [value]
return [fdt32_to_cpu(v) for v in value]
def GetPhandleNameOffset(node, propname):
"""Get a <&phandle>, "string", <offset> value from a property
Args:
node: Node object to read from
propname: property name to read
Returns:
tuple:
Node object
str
int
or None if the property does not exist
"""
prop = node.props.get(propname)
if not prop:
return None
value = prop.bytes
phandle = fdt32_to_cpu(value[:4])
node = node.GetFdt().LookupPhandle(phandle)
name = ''
for byte in value[4:]:
if not byte:
break
name += chr(byte)
val = fdt32_to_cpu(value[4 + len(name) + 1:])
return node, name, val
def GetDatatype(node, propname, datatype):
"""Get a value of a given type from a property

View file

@ -32,6 +32,7 @@
u-boot,dm-pre-reloc;
compatible = "source";
clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
phandle-name-offset = <&phandle_2>, "fred", <123>;
};
phandle-source2 {

View file

@ -929,6 +929,7 @@ U_BOOT_DRVINFO(spl_test) = {
self._check_strings(HEADER + '''
struct dtd_source {
\tstruct phandle_2_arg clocks[4];
\tunsigned char phandle_name_offset[13];
};
struct dtd_target {
\tfdt32_t\t\tintval;
@ -981,6 +982,8 @@ static struct dtd_source dtv_phandle_source = {
\t\t\t{0, {11}},
\t\t\t{1, {12, 13}},
\t\t\t{4, {}},},
\t.phandle_name_offset = {0x0, 0x0, 0x0, 0x3, 0x66, 0x72, 0x65, 0x64,
\t\t0x0, 0x0, 0x0, 0x0, 0x7b},
};
U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",

View file

@ -795,6 +795,17 @@ class TestFdtUtil(unittest.TestCase):
finally:
tools.outdir= old_outdir
def test_get_phandle_name_offset(self):
val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
self.assertIsNone(val)
dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source')
node, name, offset = fdt_util.GetPhandleNameOffset(node,
'phandle-name-offset')
self.assertEqual('phandle3-target', node.name)
self.assertEqual('fred', name)
self.assertEqual(123, offset)
def run_test_coverage(build_dir):
"""Run the tests and check that we get 100% coverage

View file

@ -36,8 +36,10 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true,
false);
if (tfd < 0)
if (tfd < 0) {
fprintf(stderr, "Cannot map FDT file '%s'\n", tmpfile);
return -EIO;
}
if (params->keydest) {
struct stat dest_sbuf;

View file

@ -1292,8 +1292,12 @@ int fit_add_verification_data(const char *keydir, const char *keyfile,
ret = fit_image_add_verification_data(keydir, keyfile, keydest,
fit, noffset, comment, require_keys, engine_id,
cmdname, algo_name);
if (ret)
if (ret) {
printf("Can't add verification data for node '%s' (%s)\n",
fdt_get_name(fit, noffset, NULL),
fdt_strerror(ret));
return ret;
}
}
/* If there are no keys, we can't sign configurations */

View file

@ -0,0 +1 @@
../../.checkpatch.conf

View file

@ -211,7 +211,7 @@ def check_patch(fname, verbose=False, show_types=False, use_tree=False):
stdout: Full output of checkpatch
"""
chk = find_check_patch()
args = [chk, '--u-boot', '--strict']
args = [chk]
if not use_tree:
args.append('--no-tree')
if show_types:

View file

@ -81,14 +81,15 @@ static void outf(int level, const char *fmt, ...)
static void usage(void)
{
fprintf(stderr,
"Usage: proftool -cds -v3 <cmd> <profdata>\n"
"Usage: proftool [-cmtv] <cmd> <profdata>\n"
"\n"
"Commands\n"
" dump-ftrace\t\tDump out textual data in ftrace format\n"
"\n"
"Options:\n"
" -c <cfg>\tSpecific config file\n"
" -m <map>\tSpecify Systen.map file\n"
" -t <trace>\tSpecific trace data file (from U-Boot)\n"
" -t <fname>\tSpecify trace data file (from U-Boot 'trace calls')\n"
" -v <0-4>\tSpecify verbosity\n");
exit(EXIT_FAILURE);
}
@ -162,7 +163,7 @@ static int read_data(FILE *fin, void *buff, int size)
if (!err)
return 1;
if (err != size) {
error("Cannot read profile file at pos %ld\n", ftell(fin));
error("Cannot read profile file at pos %lx\n", ftell(fin));
return -1;
}
return 0;
@ -495,10 +496,17 @@ static int make_ftrace(void)
int missing_count = 0, skip_count = 0;
int i;
printf("# tracer: ftrace\n"
"#\n"
"# TASK-PID CPU# TIMESTAMP FUNCTION\n"
"# | | | | |\n");
printf("# tracer: function\n"
"#\n"
"# entries-in-buffer/entries-written: 140080/250280 #P:4\n"
"#\n"
"# _-----=> irqs-off\n"
"# / _----=> need-resched\n"
"# | / _---=> hardirq/softirq\n"
"# || / _--=> preempt-depth\n"
"# ||| / delay\n"
"# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n"
"# | | | |||| | |\n");
for (i = 0, call = call_list; i < call_count; i++, call++) {
struct func_info *func = find_func_by_offset(call->func);
ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
@ -520,7 +528,7 @@ static int make_ftrace(void)
continue;
}
printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
printf("%16s-%-5d [000] .... %lu.%06lu: ", "uboot", 1,
time / 1000000, time % 1000000);
out_func(call->func, 0, " <- ");
@ -562,23 +570,23 @@ static int prof_tool(int argc, char *const argv[],
int main(int argc, char *argv[])
{
const char *map_fname = "System.map";
const char *prof_fname = NULL;
const char *trace_config_fname = NULL;
const char *trace_fname = NULL;
const char *config_fname = NULL;
int opt;
verbose = 2;
while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
while ((opt = getopt(argc, argv, "c:m:t:v:")) != -1) {
switch (opt) {
case 'c':
config_fname = optarg;
break;
case 'm':
map_fname = optarg;
break;
case 'p':
prof_fname = optarg;
break;
case 't':
trace_config_fname = optarg;
trace_fname = optarg;
break;
case 'v':
@ -594,6 +602,5 @@ int main(int argc, char *argv[])
usage();
debug("Debug enabled\n");
return prof_tool(argc, argv, prof_fname, map_fname,
trace_config_fname);
return prof_tool(argc, argv, trace_fname, map_fname, config_fname);
}