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
diff --git a/.gitignore b/.gitignore
index eb769f1..3adf1fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
# Normal rules (sorted alphabetically)
#
.*
+!.checkpatch.conf
*.a
*.asn1.[ch]
*.bin
diff --git a/Makefile b/Makefile
index a4a14d5..eb354c0 100644
--- a/Makefile
+++ b/Makefile
@@ -1006,14 +1006,9 @@
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 @@
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 @@
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)
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c
index f4a045e..9d981cc 100644
--- a/arch/arm/cpu/armv7/s5p-common/timer.c
+++ b/arch/arm/cpu/armv7/s5p-common/timer.c
@@ -82,7 +82,7 @@
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;
diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c
index f27a74b..8f83372 100644
--- a/arch/arm/cpu/armv8/generic_timer.c
+++ b/arch/arm/cpu/armv8/generic_timer.c
@@ -17,7 +17,7 @@
/*
* 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 @@
/*
* 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 @@
}
#endif
-uint64_t get_ticks(void)
+uint64_t notrace get_ticks(void)
{
unsigned long ticks = timer_read_counter();
diff --git a/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi b/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi
index e8a34c7..1325e0c 100644
--- a/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi
+++ b/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi
@@ -17,7 +17,7 @@
&binman {
simple-bin {
- blob {
+ fit {
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
};
};
diff --git a/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi b/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi
index d2349ae..088861d 100644
--- a/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi
@@ -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>;
};
diff --git a/arch/arm/dts/rk3399-u-boot.dtsi b/arch/arm/dts/rk3399-u-boot.dtsi
index 3c1a15f..8a0b180 100644
--- a/arch/arm/dts/rk3399-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-u-boot.dtsi
@@ -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;
diff --git a/arch/arm/dts/rockchip-u-boot.dtsi b/arch/arm/dts/rockchip-u-boot.dtsi
index fa094b0..234fc5d 100644
--- a/arch/arm/dts/rockchip-u-boot.dtsi
+++ b/arch/arm/dts/rockchip-u-boot.dtsi
@@ -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 */
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h
index fb5fdaf..dab148e 100644
--- a/arch/arm/mach-exynos/include/mach/cpu.h
+++ b/arch/arm/mach-exynos/include/mach/cpu.h
@@ -248,7 +248,7 @@
}
#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(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 @@
#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()) { \
diff --git a/arch/arm/mach-rockchip/make_fit_atf.py b/arch/arm/mach-rockchip/make_fit_atf.py
deleted file mode 100755
index 08cfe9f..0000000
--- a/arch/arm/mach-rockchip/make_fit_atf.py
+++ /dev/null
@@ -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()
diff --git a/arch/arm/mach-rockchip/tpl.c b/arch/arm/mach-rockchip/tpl.c
index ed46a9a..fdd0c59 100644
--- a/arch/arm/mach-rockchip/tpl.c
+++ b/arch/arm/mach-rockchip/tpl.c
@@ -4,6 +4,7 @@
*/
#include <common.h>
+#include <bootstage.h>
#include <debug_uart.h>
#include <dm.h>
#include <hang.h>
@@ -70,15 +71,15 @@
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 @@
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;
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 23693f8..22d103d 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -137,7 +137,7 @@
#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;
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 3e613de..27764fc 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -71,7 +71,7 @@
#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);
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index 4cf41e9..8f38c2d 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -108,7 +108,7 @@
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));
diff --git a/boot/Kconfig b/boot/Kconfig
index 48fa15e..fdcfbae 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -282,12 +282,11 @@
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
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 08da7fe..0e026bb 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -599,6 +599,7 @@
debug("Ignoring compatible = %s property\n",
compatible);
}
+ return 0;
ret = fpga_load(devnum, (void *)fpga_image->load_addr,
fpga_image->size, BIT_FULL, flags);
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index fe3346f..ad46a74 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -179,3 +179,4 @@
CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig
index 2fac79b..3440062 100644
--- a/configs/evb-ast2600_defconfig
+++ b/configs/evb-ast2600_defconfig
@@ -120,3 +120,4 @@
CONFIG_SHA384=y
CONFIG_HEXDUMP=y
# CONFIG_EFI_LOADER is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig
index fcfb6aa..5c6b1d5 100644
--- a/configs/evb-rk3288_defconfig
+++ b/configs/evb-rk3288_defconfig
@@ -29,6 +29,7 @@
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
diff --git a/configs/rockpro64-rk3399_defconfig b/configs/rockpro64-rk3399_defconfig
index 6422b9f..3b4820c 100644
--- a/configs/rockpro64-rk3399_defconfig
+++ b/configs/rockpro64-rk3399_defconfig
@@ -9,6 +9,7 @@
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_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_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
diff --git a/configs/sama7g5ek_mmc1_defconfig b/configs/sama7g5ek_mmc1_defconfig
index f004e44..ecb4dfc 100644
--- a/configs/sama7g5ek_mmc1_defconfig
+++ b/configs/sama7g5ek_mmc1_defconfig
@@ -79,3 +79,4 @@
CONFIG_MCHP_PIT64B_TIMER=y
CONFIG_OF_LIBFDT_OVERLAY=y
# CONFIG_EFI_LOADER_HII is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/configs/sama7g5ek_mmc_defconfig b/configs/sama7g5ek_mmc_defconfig
index 5b42fc6..1d5bccd 100644
--- a/configs/sama7g5ek_mmc_defconfig
+++ b/configs/sama7g5ek_mmc_defconfig
@@ -79,3 +79,4 @@
CONFIG_MCHP_PIT64B_TIMER=y
CONFIG_OF_LIBFDT_OVERLAY=y
# CONFIG_EFI_LOADER_HII is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/doc/develop/trace.rst b/doc/develop/trace.rst
index b22e068..5c7802d 100644
--- a/doc/develop/trace.rst
+++ b/doc/develop/trace.rst
@@ -185,7 +185,7 @@
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.
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index ce2d5dd..a1b85ca 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -403,13 +403,6 @@
{
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;
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 12355af..aa61a0f 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -555,15 +555,6 @@
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.
* However, if not then for the moment nothing is done, since this function
diff --git a/lib/Kconfig b/lib/Kconfig
index 980bbc4..549bd35 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -316,7 +316,7 @@
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 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 @@
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 @@
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"
diff --git a/lib/Makefile b/lib/Makefile
index d77b33e..a282e40 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,12 +57,13 @@
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/
diff --git a/lib/efi_loader/efi_freestanding.c b/lib/efi_loader/efi_freestanding.c
index c85df02..4b65fc6 100644
--- a/lib/efi_loader/efi_freestanding.c
+++ b/lib/efi_loader/efi_freestanding.c
@@ -100,7 +100,7 @@
* 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 @@
* 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)
{
}
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 64c5b3d..0827e16 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -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 @@
* 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 @@
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,37 +626,10 @@
* FDT (prior to console ready) will need to make their own
* arrangements and do their own checks.
*/
- assert(!fdtdec_prepare_fdt());
+ assert(!fdtdec_prepare_fdt(gd->fdt_blob));
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;
- }
- return 0;
-}
-
int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
{
const u32 *phandle;
@@ -1229,6 +1234,29 @@
#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 @@
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 @@
*rescan = 1;
gd->fdt_blob = fdt_blob;
- return fdtdec_prepare_fdt();
+ return fdtdec_prepare_fdt(fdt_blob);
}
/*
diff --git a/lib/trace.c b/lib/trace.c
index 54f0bf2..b9dc6d2 100644
--- a/lib/trace.c
+++ b/lib/trace.c
@@ -40,7 +40,8 @@
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 @@
/**
* 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 @@
* 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 @@
#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 @@
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 @@
* @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 @@
* @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 @@
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 @@
* @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 @@
*
* 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;
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 69e4b00..fa8abdc 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -487,6 +487,14 @@
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` 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 @@
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 @@
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 @@
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 @@
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
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 964c698..e647400 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -552,6 +552,7 @@
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 @@
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 @@
"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:
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index fe50bf5..3cc8a38 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -210,7 +210,31 @@
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 @@
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 @@
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 @@
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
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index 75b867c..082a3e1 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -348,6 +348,16 @@
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()
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 3dc32db..2b32c13 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -216,11 +216,11 @@
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:
Entry: blob-ext: Externally built binary blob
@@ -1178,11 +1178,13 @@
- 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 @@
};
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 @@
};
};
+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 @@
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";
@@ -1270,6 +1276,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:
@@ -1478,6 +1498,10 @@
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,13 +1521,48 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
+.. _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
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 1be31a0..5d8696e 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -73,7 +73,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
# 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 @@
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 @@
# 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 @@
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
diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py
index 6960048..1c1efb2 100644
--- a/tools/binman/etype/_testing.py
+++ b/tools/binman/etype/_testing.py
@@ -63,6 +63,7 @@
'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 @@
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):
diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py
index a50a806..c7ddced 100644
--- a/tools/binman/etype/blob.py
+++ b/tools/binman/etype/blob.py
@@ -35,11 +35,17 @@
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,
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 7860e2a..0e9d81b 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -392,8 +392,8 @@
_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 @@
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 @@
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 @@
# 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 @@
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.
diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py
index c2288c4..cb264c3c 100644
--- a/tools/binman/etype/mkimage.py
+++ b/tools/binman/etype/mkimage.py
@@ -57,24 +57,24 @@
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::
diff --git a/tools/binman/etype/null.py b/tools/binman/etype/null.py
new file mode 100644
index 0000000..c10d482
--- /dev/null
+++ b/tools/binman/etype/null.py
@@ -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
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index da561e2..57b91ff 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -144,6 +144,10 @@
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 @@
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 @@
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 @@
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 @@
# 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 @@
"""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 @@
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 @@
(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 @@
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 @@
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 @@
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 @@
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 @@
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
diff --git a/tools/binman/etype/tee_os.py b/tools/binman/etype/tee_os.py
index 6ce4b67..5529727 100644
--- a/tools/binman/etype/tee_os.py
+++ b/tools/binman/etype/tee_os.py
@@ -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
diff --git a/tools/binman/etype/u_boot.py b/tools/binman/etype/u_boot.py
index e8d180a..d5639ee 100644
--- a/tools/binman/etype/u_boot.py
+++ b/tools/binman/etype/u_boot.py
@@ -18,11 +18,7 @@
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.
diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py
index d1aa3b4..7f710c8 100644
--- a/tools/binman/etype/u_boot_spl.py
+++ b/tools/binman/etype/u_boot_spl.py
@@ -21,9 +21,7 @@
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 @@
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'
diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py
index 50a126d..e7ec329 100644
--- a/tools/binman/etype/u_boot_spl_nodtb.py
+++ b/tools/binman/etype/u_boot_spl_nodtb.py
@@ -21,9 +21,7 @@
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.
diff --git a/tools/binman/etype/u_boot_tpl.py b/tools/binman/etype/u_boot_tpl.py
index 1883a2b..397b9f8 100644
--- a/tools/binman/etype/u_boot_tpl.py
+++ b/tools/binman/etype/u_boot_tpl.py
@@ -21,9 +21,7 @@
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.
diff --git a/tools/binman/etype/u_boot_tpl_nodtb.py b/tools/binman/etype/u_boot_tpl_nodtb.py
index 7e08e58..9bb2b5d 100644
--- a/tools/binman/etype/u_boot_tpl_nodtb.py
+++ b/tools/binman/etype/u_boot_tpl_nodtb.py
@@ -21,9 +21,7 @@
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.
diff --git a/tools/binman/etype/u_boot_vpl.py b/tools/binman/etype/u_boot_vpl.py
index 62e5969..31d7e83 100644
--- a/tools/binman/etype/u_boot_vpl.py
+++ b/tools/binman/etype/u_boot_vpl.py
@@ -21,9 +21,7 @@
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.
diff --git a/tools/binman/etype/u_boot_vpl_nodtb.py b/tools/binman/etype/u_boot_vpl_nodtb.py
index db3d8a9..64c2767 100644
--- a/tools/binman/etype/u_boot_vpl_nodtb.py
+++ b/tools/binman/etype/u_boot_vpl_nodtb.py
@@ -21,11 +21,7 @@
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.
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 62ee86b..be0aea4 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -112,6 +112,8 @@
# 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 @@
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 @@
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 @@
'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()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index 6d4bff5..b84dd21 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -94,9 +94,6 @@
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')
diff --git a/tools/binman/test/261_section_fname.dts b/tools/binman/test/261_section_fname.dts
new file mode 100644
index 0000000..790381e
--- /dev/null
+++ b/tools/binman/test/261_section_fname.dts
@@ -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 {
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/262_absent.dts b/tools/binman/test/262_absent.dts
new file mode 100644
index 0000000..2ab8766
--- /dev/null
+++ b/tools/binman/test/262_absent.dts
@@ -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 {
+ };
+ };
+};
diff --git a/tools/binman/test/263_tee_os_opt.dts b/tools/binman/test/263_tee_os_opt.dts
new file mode 100644
index 0000000..2e4ec24
--- /dev/null
+++ b/tools/binman/test/263_tee_os_opt.dts
@@ -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 {
+ };
+ };
+};
diff --git a/tools/binman/test/264_tee_os_opt_fit.dts b/tools/binman/test/264_tee_os_opt_fit.dts
new file mode 100644
index 0000000..ae44b43
--- /dev/null
+++ b/tools/binman/test/264_tee_os_opt_fit.dts
@@ -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 {
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/265_tee_os_opt_fit_bad.dts b/tools/binman/test/265_tee_os_opt_fit_bad.dts
new file mode 100644
index 0000000..7fa363c
--- /dev/null
+++ b/tools/binman/test/265_tee_os_opt_fit_bad.dts
@@ -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 {
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/266_blob_ext_opt.dts b/tools/binman/test/266_blob_ext_opt.dts
new file mode 100644
index 0000000..7171531
--- /dev/null
+++ b/tools/binman/test/266_blob_ext_opt.dts
@@ -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;
+ };
+ };
+};
diff --git a/tools/binman/test/267_section_inner.dts b/tools/binman/test/267_section_inner.dts
new file mode 100644
index 0000000..f6faab3
--- /dev/null
+++ b/tools/binman/test/267_section_inner.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ section {
+ size = <0x10>;
+ u-boot {
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/268_null.dts b/tools/binman/test/268_null.dts
new file mode 100644
index 0000000..3824ba8
--- /dev/null
+++ b/tools/binman/test/268_null.dts
@@ -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 {
+ };
+ };
+};
diff --git a/tools/binman/test/269_overlap.dts b/tools/binman/test/269_overlap.dts
new file mode 100644
index 0000000..f949b8b
--- /dev/null
+++ b/tools/binman/test/269_overlap.dts
@@ -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;
+ };
+ };
+};
diff --git a/tools/binman/test/270_overlap_null.dts b/tools/binman/test/270_overlap_null.dts
new file mode 100644
index 0000000..feed9ec
--- /dev/null
+++ b/tools/binman/test/270_overlap_null.dts
@@ -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 {
+ };
+ };
+};
diff --git a/tools/binman/test/271_overlap_bad.dts b/tools/binman/test/271_overlap_bad.dts
new file mode 100644
index 0000000..f281802
--- /dev/null
+++ b/tools/binman/test/271_overlap_bad.dts
@@ -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;
+ };
+ };
+};
diff --git a/tools/binman/test/272_overlap_no_size.dts b/tools/binman/test/272_overlap_no_size.dts
new file mode 100644
index 0000000..4517536
--- /dev/null
+++ b/tools/binman/test/272_overlap_no_size.dts
@@ -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;
+ };
+ };
+};
diff --git a/tools/binman/test/273_blob_symbol.dts b/tools/binman/test/273_blob_symbol.dts
new file mode 100644
index 0000000..87b0aba
--- /dev/null
+++ b/tools/binman/test/273_blob_symbol.dts
@@ -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;
+ };
+ };
+};
diff --git a/tools/binman/test/274_offset_from_elf.dts b/tools/binman/test/274_offset_from_elf.dts
new file mode 100644
index 0000000..e3372fc
--- /dev/null
+++ b/tools/binman/test/274_offset_from_elf.dts
@@ -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;
+ };
+ };
+};
diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile
index bea8567..cd66a30 100644
--- a/tools/binman/test/Makefile
+++ b/tools/binman/test/Makefile
@@ -30,11 +30,12 @@
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_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
diff --git a/tools/binman/test/blob_syms.c b/tools/binman/test/blob_syms.c
new file mode 100644
index 0000000..d652c79
--- /dev/null
+++ b/tools/binman/test/blob_syms.c
@@ -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);
diff --git a/tools/binman/test/blob_syms.lds b/tools/binman/test/blob_syms.lds
new file mode 100644
index 0000000..787e38d
--- /dev/null
+++ b/tools/binman/test/blob_syms.lds
@@ -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*) }
+
+}
diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py
index d7c38ad..f343166 100644
--- a/tools/dtoc/fdt_util.py
+++ b/tools/dtoc/fdt_util.py
@@ -281,6 +281,34 @@
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
diff --git a/tools/dtoc/test/dtoc_test_phandle.dts b/tools/dtoc/test/dtoc_test_phandle.dts
index a71acff..d9aa433 100644
--- a/tools/dtoc/test/dtoc_test_phandle.dts
+++ b/tools/dtoc/test/dtoc_test_phandle.dts
@@ -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 {
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 879ca2a..c62fcba 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -929,6 +929,7 @@
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 @@
\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",
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index a3e36ea..3b8ee00 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -795,6 +795,17 @@
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
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 923a975..8a18b1b 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -36,8 +36,10 @@
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;
diff --git a/tools/image-host.c b/tools/image-host.c
index 4e0512b..4a24dee 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -1292,8 +1292,12 @@
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 */
diff --git a/tools/patman/.checkpatch.conf b/tools/patman/.checkpatch.conf
new file mode 120000
index 0000000..c0e2020
--- /dev/null
+++ b/tools/patman/.checkpatch.conf
@@ -0,0 +1 @@
+../../.checkpatch.conf
\ No newline at end of file
diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py
index 012c0d8..d1b902d 100644
--- a/tools/patman/checkpatch.py
+++ b/tools/patman/checkpatch.py
@@ -211,7 +211,7 @@
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:
diff --git a/tools/proftool.c b/tools/proftool.c
index ea7d07a..b66ea55 100644
--- a/tools/proftool.c
+++ b/tools/proftool.c
@@ -81,14 +81,15 @@
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 @@
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 @@
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 @@
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 @@
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 'm':
- map_fname = optarg;
+ case 'c':
+ config_fname = optarg;
break;
- case 'p':
- prof_fname = optarg;
+ case 'm':
+ map_fname = optarg;
break;
case 't':
- trace_config_fname = optarg;
+ trace_fname = optarg;
break;
case 'v':
@@ -594,6 +602,5 @@
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);
}