diff options
author | Tom Rini <trini@konsulko.com> | 2023-01-19 09:46:57 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-01-19 09:46:57 -0500 |
commit | 53c47c59e638cc118c272235db516bb541dad0ac (patch) | |
tree | cd40236202c66c25e6f311f2654ebcfa087ed2b1 | |
parent | 7aec35be4b5fa7aabc0ece03dc8825495d86a1be (diff) | |
parent | 4c5907889553696160fabaa7e9f0c96ed1fa6597 (diff) | |
download | u-boot-WIP/19Jan2023.zip u-boot-WIP/19Jan2023.tar.gz u-boot-WIP/19Jan2023.tar.bz2 |
Merge tag 'dm-pull-18jan23' of https://source.denx.de/u-boot/custodians/u-boot-dmWIP/19Jan2023
convert rockchip to use binman
patman fix for checkpatch
binman optional entries, improved support for ELF symbols
trace improvements
minor fdt refactoring
78 files changed, 1617 insertions, 537 deletions
@@ -6,6 +6,7 @@ # Normal rules (sorted alphabetically) # .* +!.checkpatch.conf *.a *.asn1.[ch] *.bin @@ -1006,14 +1006,9 @@ ifeq ($(CONFIG_INIT_SP_RELATIVE)$(CONFIG_OF_SEPARATE),yy) INPUTS-y += init_sp_bss_offset_check endif -ifeq ($(CONFIG_ARCH_ROCKCHIP)$(CONFIG_SPL),yy) -# Binman image dependencies -ifeq ($(CONFIG_ARM64),y) -INPUTS-y += u-boot.itb -else +ifeq ($(CONFIG_ARCH_ROCKCHIP)_$(CONFIG_SPL_FRAMEWORK),y_) INPUTS-y += u-boot.img endif -endif INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \ $(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \ @@ -1370,9 +1365,6 @@ $(U_BOOT_ITS): $(subst ",,$(CONFIG_SPL_FIT_SOURCE)) else ifneq ($(CONFIG_USE_SPL_FIT_GENERATOR),) U_BOOT_ITS := u-boot.its -ifeq ($(CONFIG_SPL_FIT_GENERATOR),"arch/arm/mach-rockchip/make_fit_atf.py") -U_BOOT_ITS_DEPS += u-boot -endif $(U_BOOT_ITS): $(U_BOOT_ITS_DEPS) FORCE $(srctree)/$(CONFIG_SPL_FIT_GENERATOR) \ $(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) > $@ @@ -1477,7 +1469,6 @@ OBJCOPYFLAGS_u-boot-with-spl.bin = -I binary -O binary \ u-boot-with-spl.bin: $(SPL_IMAGE) $(SPL_PAYLOAD) FORCE $(call if_changed,pad_cat) - ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy) MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE) 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 @@ unsigned long get_timer(unsigned long base) return time_ms - base; } -unsigned long __attribute__((no_instrument_function)) timer_get_us(void) +unsigned long notrace timer_get_us(void) { static unsigned long base_time_us; 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 @@ DECLARE_GLOBAL_DATA_PTR; /* * Generic timer implementation of get_tbclk() */ -unsigned long get_tbclk(void) +unsigned long notrace get_tbclk(void) { unsigned long cntfrq; asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq)); @@ -78,7 +78,7 @@ unsigned long timer_read_counter(void) /* * timer_read_counter() using the Arm Generic Timer (aka arch timer). */ -unsigned long timer_read_counter(void) +unsigned long notrace timer_read_counter(void) { unsigned long cntpct; @@ -89,7 +89,7 @@ unsigned long timer_read_counter(void) } #endif -uint64_t get_ticks(void) +uint64_t notrace get_ticks(void) { unsigned long ticks = timer_read_counter(); 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 @@ static inline char *s5p_get_cpu_name(void) } #define IS_SAMSUNG_TYPE(type, id) \ -static inline int __attribute__((no_instrument_function)) cpu_is_##type(void) \ +static inline int notrace cpu_is_##type(void) \ { \ return (s5p_cpu_id >> 12) == id; \ } @@ -257,7 +257,7 @@ IS_SAMSUNG_TYPE(exynos4, 0x4) IS_SAMSUNG_TYPE(exynos5, 0x5) #define IS_EXYNOS_TYPE(type, id) \ -static inline int __attribute__((no_instrument_function)) \ +static inline int notrace \ proid_is_##type(void) \ { \ return s5p_cpu_id == id; \ @@ -272,7 +272,7 @@ IS_EXYNOS_TYPE(exynos5422, 0x5422) #define proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422()) #define SAMSUNG_BASE(device, base) \ -static inline unsigned long __attribute__((no_instrument_function)) \ +static inline unsigned long notrace \ samsung_get_base_##device(void) \ { \ if (cpu_is_exynos4()) { \ 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 @@ void board_init_f(ulong dummy) U_BOOT_TIME ")\n"); #endif #endif + /* Init secure timer */ + rockchip_stimer_init(); + ret = spl_early_init(); if (ret) { debug("spl_early_init() failed: %d\n", ret); hang(); } - /* Init secure timer */ - rockchip_stimer_init(); - /* Init ARM arch timer */ if (IS_ENABLED(CONFIG_SYS_ARCH_TIMER)) timer_init(); @@ -93,6 +94,15 @@ void board_init_f(ulong dummy) int board_return_to_bootrom(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { +#ifdef CONFIG_BOOTSTAGE_STASH + int ret; + + bootstage_mark_name(BOOTSTAGE_ID_END_TPL, "end tpl"); + ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR, + CONFIG_BOOTSTAGE_STASH_SIZE); + if (ret) + debug("Failed to stash bootstage: err=%d\n", ret); +#endif back_to_bootrom(BROM_BOOT_NEXTSTAGE); return 0; 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 @@ struct arch_global_data { #define DECLARE_GLOBAL_DATA_PTR extern struct global_data *global_data_ptr # else -static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void) +static inline notrace gd_t *get_fs_gd_ptr(void) { gd_t *gd_ptr; 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 @@ static inline unsigned long long native_read_tscp(unsigned int *aux) #define EAX_EDX_RET(val, low, high) "=A" (val) #endif -static inline __attribute__((no_instrument_function)) +static inline notrace unsigned long long native_read_msr(unsigned int msr) { DECLARE_ARGS(val, low, high); 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 @@ void board_init_f_r(void) __attribute__ ((noreturn)); int arch_misc_init(void); /* Read the time stamp counter */ -static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void) +static inline notrace uint64_t rdtsc(void) { uint32_t high, low; __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); diff --git a/boot/Kconfig b/boot/Kconfig index 48fa15e..fdcfbae 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -282,12 +282,11 @@ config SPL_FIT_SOURCE config USE_SPL_FIT_GENERATOR bool "Use a script to generate the .its script" depends on SPL_FIT - default y if !ARCH_SUNXI && !RISCV + default y if SPL_FIT && ARCH_ZYNQMP config SPL_FIT_GENERATOR string ".its file generator script for U-Boot FIT image" depends on USE_SPL_FIT_GENERATOR - default "arch/arm/mach-rockchip/make_fit_atf.py" if SPL_LOAD_FIT && ARCH_ROCKCHIP default "arch/arm/mach-zynqmp/mkimage_fit_atf.sh" if SPL_LOAD_FIT && ARCH_ZYNQMP help Specifies a (platform specific) script file to generate the FIT 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 @@ static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node, debug("Ignoring compatible = %s property\n", compatible); } + return 0; ret = fpga_load(devnum, (void *)fpga_image->load_addr, fpga_image->size, BIT_FULL, flags); 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_VENDOR_NUM=0x0451 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_WDT=y 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_SILENT_CONSOLE=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_PAD_TO=0x7f8000 CONFIG_SPL_NO_BSS_LIMIT=y +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_STACK=0xff718000 CONFIG_SPL_STACK_R=y 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_ENV_OFFSET=0x3F8000 CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64" CONFIG_ROCKCHIP_RK3399=y CONFIG_TARGET_ROCKPRO64_RK3399=y +CONFIG_BOOTSTAGE_STASH_ADDR=0xff8e0000 CONFIG_DEBUG_UART_BASE=0xFF1A0000 CONFIG_DEBUG_UART_CLOCK=24000000 CONFIG_SPL_SPI_FLASH_SUPPORT=y @@ -17,6 +18,12 @@ CONFIG_SYS_LOAD_ADDR=0x800800 CONFIG_DEBUG_UART=y CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x300000 +CONFIG_BOOTSTAGE=y +CONFIG_SPL_BOOTSTAGE=y +CONFIG_TPL_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10 +CONFIG_BOOTSTAGE_STASH=y CONFIG_USE_PREBOOT=y CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-rockpro64.dtb" CONFIG_DISPLAY_BOARDINFO_LATE=y @@ -40,6 +47,7 @@ CONFIG_CMD_PCI=y CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_TIME=y +CONFIG_CMD_BOOTSTAGE=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" CONFIG_ENV_IS_IN_SPI_FLASH=y 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_TIMER=y 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_TIMER=y 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 produces sensible results for your board. Suitable sources for this timer include high resolution timers, PWMs or profile timers if available. Most modern SOCs have a suitable timer for this. Make sure that you mark this timer (and anything it calls) with -__attribute__((no_instrument_function)) so that the trace library can +notrace so that the trace library can use it without causing an infinite loop. 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 @@ static int __maybe_unused pinctrl_post_bind(struct udevice *dev) { const struct pinctrl_ops *ops = pinctrl_get_ops(dev); - /* - * Make sure that the pinctrl driver gets probed after binding - * as some pinctrl drivers also register the GPIO driver during - * probe, and if they are not probed GPIO-s are not registered. - */ - dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); - if (!ops) { dev_dbg(dev, "ops is not set. Do not bind.\n"); return -EINVAL; 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 @@ uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, int fdtdec_get_is_enabled(const void *blob, int node); /** - * Make sure we have a valid fdt available to control U-Boot. - * - * If not, a message is printed to the console if the console is ready. - * - * Return: 0 if all ok, -1 if not - */ -int fdtdec_prepare_fdt(void); - -/** * Checks that we have a valid fdt available to control U-Boot. * 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 BITREVERSE config TRACE bool "Support for tracing of function calls and timing" imply CMD_TRACE - select TIMER_EARLY + imply TIMER_EARLY help Enables function tracing within U-Boot. This allows recording of call traces including timing information. The command can write data to @@ -422,6 +422,7 @@ config TPM config SPL_TPM bool "Trusted Platform Module (TPM) Support in SPL" depends on SPL_DM + imply SPL_CRC8 help This enables support for TPMs which can be used to provide security features for your board. The TPM can be connected via LPC or I2C @@ -617,6 +618,23 @@ config SPL_MD5 security applications, but it can be useful for providing a quick checksum of a block of data. +config CRC8 + def_bool y + help + Enables CRC8 support in U-Boot. This is normally required. CRC8 is + a simple and fast checksumming algorithm which does a bytewise + checksum with feedback to produce an 8-bit result. The code is small + and it does not require a lookup table (unlike CRC32). + +config SPL_CRC8 + bool "Support CRC8 in SPL" + depends on SPL + help + Enables CRC8 support in SPL. This is not normally required. CRC8 is + a simple and fast checksumming algorithm which does a bytewise + checksum with feedback to produce an 8-bit result. The code is small + and it does not require a lookup table (unlike CRC32). + config CRC32 def_bool y help @@ -1042,6 +1060,13 @@ config LMB_RESERVED_REGIONS Define the number of supported reserved regions in the library logical memory blocks. +config PHANDLE_CHECK_SEQ + bool "Enable phandle check while getting sequence number" + help + When there are multiple device tree nodes with same name, + enable this config option to distinguish them using + phandles in fdtdec_get_alias_seq() function. + endmenu menu "FWU Multi Bank Updates" diff --git a/lib/Makefile b/lib/Makefile index d77b33e..a282e40 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -57,12 +57,13 @@ endif obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o ifeq ($(CONFIG_$(SPL_TPL_)TPM),y) -obj-y += crc8.o obj-$(CONFIG_TPM) += tpm_api.o obj-$(CONFIG_TPM_V1) += tpm-v1.o obj-$(CONFIG_TPM_V2) += tpm-v2.o endif +obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o + obj-y += crypto/ obj-$(CONFIG_$(SPL_TPL_)GENERATE_ACPI_TABLE) += acpi/ 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 @@ void *memset(void *s, int c, size_t n) * func_ptr: Pointer to function being entered * caller: Pointer to function which called this function */ -void __attribute__((no_instrument_function)) +void notrace __cyg_profile_func_enter(void *func_ptr, void *caller) { } @@ -116,7 +116,7 @@ __cyg_profile_func_enter(void *func_ptr, void *caller) * func_ptr: Pointer to function being entered * caller: Pointer to function which called this function */ -void __attribute__((no_instrument_function)) +void notrace __cyg_profile_func_exit(void *func_ptr, void *caller) { } 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 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset, * Adding an extra check to distinguish DT nodes with * same name */ - if (offset != fdt_path_offset(blob, prop)) - continue; + if (IS_ENABLED(CONFIG_PHANDLE_CHECK_SEQ)) { + if (fdt_get_phandle(blob, offset) != + fdt_get_phandle(blob, fdt_path_offset(blob, prop))) + continue; + } val = trailing_strtol(name); if (val != -1) { @@ -586,6 +590,34 @@ int fdtdec_get_chosen_node(const void *blob, const char *name) return fdt_path_offset(blob, prop); } +/** + * fdtdec_prepare_fdt() - Check we have a valid fdt available to control U-Boot + * + * @blob: Blob to check + * + * If not, a message is printed to the console if the console is ready. + * + * Return: 0 if all ok, -ENOENT if not + */ +static int fdtdec_prepare_fdt(const void *blob) +{ + if (!blob || ((uintptr_t)blob & 3) || fdt_check_header(blob)) { + if (spl_phase() <= PHASE_SPL) { + puts("Missing DTB\n"); + } else { + printf("No valid device tree binary found at %p\n", + blob); + if (_DEBUG && blob) { + printf("fdt_blob=%p\n", blob); + print_buffer((ulong)blob, blob, 4, 32, 0); + } + } + return -ENOENT; + } + + return 0; +} + int fdtdec_check_fdt(void) { /* @@ -594,34 +626,7 @@ int fdtdec_check_fdt(void) * FDT (prior to console ready) will need to make their own * arrangements and do their own checks. */ - assert(!fdtdec_prepare_fdt()); - return 0; -} - -/* - * This function is a little odd in that it accesses global data. At some - * point if the architecture board.c files merge this will make more sense. - * Even now, it is common code. - */ -int fdtdec_prepare_fdt(void) -{ - if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || - fdt_check_header(gd->fdt_blob)) { -#ifdef CONFIG_SPL_BUILD - puts("Missing DTB\n"); -#else - printf("No valid device tree binary found at %p\n", - gd->fdt_blob); -# ifdef DEBUG - if (gd->fdt_blob) { - printf("fdt_blob=%p\n", gd->fdt_blob); - print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4, - 32, 0); - } -# endif -#endif - return -1; - } + assert(!fdtdec_prepare_fdt(gd->fdt_blob)); return 0; } @@ -1229,6 +1234,29 @@ static void *fdt_find_separate(void) #else /* FDT is at end of image */ fdt_blob = (ulong *)&_end; + + if (_DEBUG && !fdtdec_prepare_fdt(fdt_blob)) { + int stack_ptr; + const void *top = fdt_blob + fdt_totalsize(fdt_blob); + + /* + * Perform a sanity check on the memory layout. If this fails, + * it indicates that the device tree is positioned above the + * global data pointer or the stack pointer. This should not + * happen. + * + * If this fails, check that SYS_INIT_SP_ADDR has enough space + * below it for SYS_MALLOC_F_LEN and global_data, as well as the + * stack, without overwriting the device tree or U-Boot itself. + * Since the device tree is sitting at _end (the start of the + * BSS region), we need the top of the device tree to be below + * any memory allocated by board_init_f_alloc_reserve(). + */ + if (top > (void *)gd || top > (void *)&stack_ptr) { + printf("FDT %p gd %p\n", fdt_blob, gd); + panic("FDT overlap"); + } + } #endif return fdt_blob; @@ -1666,7 +1694,7 @@ int fdtdec_setup(void) if (CONFIG_IS_ENABLED(MULTI_DTB_FIT)) setup_multi_dtb_fit(); - ret = fdtdec_prepare_fdt(); + ret = fdtdec_prepare_fdt(gd->fdt_blob); if (!ret) ret = fdtdec_board_setup(gd->fdt_blob); oftree_reset(); @@ -1698,7 +1726,7 @@ int fdtdec_resetup(int *rescan) *rescan = 1; gd->fdt_blob = fdt_blob; - return fdtdec_prepare_fdt(); + return fdtdec_prepare_fdt(fdt_blob); } /* 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 @@ struct trace_hdr { int max_depth; }; -static struct trace_hdr *hdr; /* Pointer to start of trace buffer */ +/* Pointer to start of trace buffer */ +static struct trace_hdr *hdr __section(".data"); static inline uintptr_t __attribute__((no_instrument_function)) func_ptr_to_num(void *func_ptr) @@ -68,7 +69,7 @@ static volatile gd_t *trace_gd; /** * trace_save_gd() - save the value of the gd register */ -static void __attribute__((no_instrument_function)) trace_save_gd(void) +static void notrace trace_save_gd(void) { trace_gd = gd; } @@ -81,7 +82,7 @@ static void __attribute__((no_instrument_function)) trace_save_gd(void) * have to set the gd register to the U-Boot value when entering a trace * point and set it back to the application value when exiting the trace point. */ -static void __attribute__((no_instrument_function)) trace_swap_gd(void) +static void notrace trace_swap_gd(void) { volatile gd_t *temp_gd = trace_gd; @@ -91,18 +92,17 @@ static void __attribute__((no_instrument_function)) trace_swap_gd(void) #else -static void __attribute__((no_instrument_function)) trace_save_gd(void) +static void notrace trace_save_gd(void) { } -static void __attribute__((no_instrument_function)) trace_swap_gd(void) +static void notrace trace_swap_gd(void) { } #endif -static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr, - void *caller, ulong flags) +static void notrace add_ftrace(void *func_ptr, void *caller, ulong flags) { if (hdr->depth > hdr->depth_limit) { hdr->ftrace_too_deep_count++; @@ -118,7 +118,7 @@ static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr, hdr->ftrace_count++; } -static void __attribute__((no_instrument_function)) add_textbase(void) +static void notrace add_textbase(void) { if (hdr->ftrace_count < hdr->ftrace_size) { struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; @@ -139,8 +139,7 @@ static void __attribute__((no_instrument_function)) add_textbase(void) * @func_ptr: pointer to function being entered * @caller: pointer to function which called this function */ -void __attribute__((no_instrument_function)) __cyg_profile_func_enter( - void *func_ptr, void *caller) +void notrace __cyg_profile_func_enter(void *func_ptr, void *caller) { if (trace_enabled) { int func; @@ -167,8 +166,7 @@ void __attribute__((no_instrument_function)) __cyg_profile_func_enter( * @func_ptr: pointer to function being entered * @caller: pointer to function which called this function */ -void __attribute__((no_instrument_function)) __cyg_profile_func_exit( - void *func_ptr, void *caller) +void notrace __cyg_profile_func_exit(void *func_ptr, void *caller) { if (trace_enabled) { trace_swap_gd(); @@ -327,7 +325,7 @@ void trace_print_stats(void) puts(" calls not traced due to depth\n"); } -void __attribute__((no_instrument_function)) trace_set_enabled(int enabled) +void notrace trace_set_enabled(int enabled) { trace_enabled = enabled != 0; } @@ -339,8 +337,7 @@ void __attribute__((no_instrument_function)) trace_set_enabled(int enabled) * @buff_size: Size of trace buffer * Return: 0 if ok */ -int __attribute__((no_instrument_function)) trace_init(void *buff, - size_t buff_size) +int notrace trace_init(void *buff, size_t buff_size) { ulong func_count = gd->mon_len / FUNC_SITE_SIZE; size_t needed; @@ -404,7 +401,7 @@ int __attribute__((no_instrument_function)) trace_init(void *buff, * * Return: 0 if ok, -ENOSPC if not enough memory is available */ -int __attribute__((no_instrument_function)) trace_early_init(void) +int notrace trace_early_init(void) { ulong func_count = gd->mon_len / FUNC_SITE_SIZE; size_t buff_size = CONFIG_TRACE_EARLY_SIZE; 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 @@ For x86 devices (with the end-at-4gb property) this base address is not added since it is assumed that images are XIP and the offsets already include the address. +While U-Boot's symbol updating is handled automatically by the u-boot-spl +entry type (and others), it is possible to use this feature with any blob. To +do this, add a `write-symbols` (boolean) property to the node, set the ELF +filename using `elf-filename` and set 'elf-base-sym' to the base symbol for the +start of the binary image (this defaults to `__image_copy_start` which is what +U-Boot uses). See `testBlobSymbol()` for an example. + +.. _binman_fdt: Access to binman entry offsets at run time (fdt) ------------------------------------------------ @@ -689,6 +697,15 @@ no-expanded: `no-expanded` property disables this just for a single entry. Put the `no-expanded` boolean property in the node to select this behaviour. +optional: + External blobs are normally required to be present for the image to be + built (but see `External blobs`_). This properly allows an entry to be + optional, so that when it is cannot be found, this problem is ignored and + an empty file is used for this blob. This should be used only when the blob + is entirely optional and is not needed for correct operation of the image. + Note that missing, optional blobs do not produce a non-zero exit code from + binman, although it does show a warning about the missing external blob. + The attributes supported for images and sections are described below. Several are similar to those for entries. @@ -782,6 +799,37 @@ align-default: symlink: Adds a symlink to the image with string given in the symlink property. +overlap: + Indicates that this entry overlaps with others in the same section. These + entries should appear at the end of the section. Overlapping entries are not + packed with other entries, but their contents are written over other entries + in the section. Overlapping entries must have an explicit offset and size. + +write-symbols: + Indicates that the blob should be updated with symbol values calculated by + binman. This is automatic for certain entry types, e.g. `u-boot-spl`. See + binman_syms_ for more information. + +elf-filename: + Sets the file name of a blob's associated ELF file. For example, if the + blob is `zephyr.bin` then the ELF file may be `zephyr.elf`. This allows + binman to locate symbols and understand the structure of the blob. See + binman_syms_ for more information. + +elf-base-sym: + Sets the name of the ELF symbol that points to the start of a blob. For + U-Boot this is `__image_copy_start` and that is the default used by binman + if this property is missing. For other projects, a difference symbol may be + needed. Add this symbol to the properties for the blob so that symbols can + be read correctly. See binman_syms_ for more information. + +offset-from-elf: + Sets the offset of an entry based on a symbol value in an another entry. + The format is <&phandle>, "sym_name", <offset> where phandle is the entry + containing the blob (with associated ELF file providing symbols), <sym_name> + is the symbol to lookup (relative to elf-base-sym) and <offset> is an offset + to add to that value. + Examples of the above options can be found in the tests. See the tools/binman/test directory. @@ -836,6 +884,11 @@ name-prefix: renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to distinguish binaries with otherwise identical names. +filename: + This allows the contents of the section to be written to a file in the + output directory. This can sometimes be useful to use the data in one + section in different image, since there is currently no way to share data + beteen images other than through files. Image Properties ---------------- @@ -1007,6 +1060,28 @@ For the BSS case, a 'spl-bss-pad' entry arg controls whether it is present. All entry args are provided by the U-Boot Makefile. +Optional entries +---------------- + +Some entries need to exist only if certain conditions are met. For example, an +entry may want to appear in the image only if a file has a particular format. +Obviously the entry must exist in the image description for it to be processed +at all, so a way needs to be found to have the entry remove itself. + +To handle this, when entry.ObtainContents() is called, the entry can call +entry.mark_absent() to mark itself as absent, passing a suitable message as the +reason. + +Any absent entries are dropped immediately after ObtainContents() has been +called on all entries. + +It is not possible for an entry to mark itself absent at any other point in the +processing. It must happen in the ObtainContents() method. + +The effect is as if the entry had never been present at all, since the image +is packed without it and it disappears from the list of entries. + + Compression ----------- @@ -1683,7 +1758,8 @@ implementation of Pack() is usually sufficient. Note: for sections, this also checks that the entries do not overlap, nor extend outside the section. If the section does not have a defined size, the size is -set large enough to hold all the entries. +set large enough to hold all the entries. For entries that are explicitly marked +as overlapping, this check is skipped. 6. SetImagePos() - sets the image position of every entry. This is the absolute position 'image-pos', as opposed to 'offset' which is relative to the containing 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 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True, image.SetAllowMissing(allow_missing) image.SetAllowFakeBlob(allow_fake_blobs) image.GetEntryContents() + image.drop_absent() image.GetEntryOffsets() # We need to pack the entries to figure out where everything @@ -593,12 +594,14 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True, image.BuildImage() if write_map: image.WriteMap() + missing_list = [] image.CheckMissing(missing_list) if missing_list: tout.warning("Image '%s' is missing external blobs and is non-functional: %s" % (image.name, ' '.join([e.name for e in missing_list]))) _ShowHelpForMissingBlobs(missing_list) + faked_list = [] image.CheckFakedBlobs(faked_list) if faked_list: @@ -606,6 +609,15 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True, "Image '%s' has faked external blobs and is non-functional: %s" % (image.name, ' '.join([os.path.basename(e.GetDefaultFilename()) for e in faked_list]))) + + optional_list = [] + image.CheckOptional(optional_list) + if optional_list: + tout.warning( + "Image '%s' is missing external blobs but is still functional: %s" % + (image.name, ' '.join([e.name for e in optional_list]))) + _ShowHelpForMissingBlobs(optional_list) + missing_bintool_list = [] image.check_missing_bintools(missing_bintool_list) if missing_bintool_list: 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 @@ def GetPackString(sym, msg): raise ValueError('%s has size %d: only 4 and 8 are supported' % (msg, sym.size)) -def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False): +def GetSymbolOffset(elf_fname, sym_name, base_sym=None): + """Read the offset of a symbol compared to base symbol + + This is useful for obtaining the value of a single symbol relative to the + base of a binary blob. + + Args: + elf_fname: Filename of the ELF file to read + sym_name (str): Name of symbol to read + base_sym (str): Base symbol to sue to calculate the offset (or None to + use '__image_copy_start' + + Returns: + int: Offset of the symbol relative to the base symbol + """ + if not base_sym: + base_sym = '__image_copy_start' + fname = tools.get_input_filename(elf_fname) + syms = GetSymbols(fname, [base_sym, sym_name]) + base = syms[base_sym].address + val = syms[sym_name].address + return val - base + +def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False, + base_sym=None): """Replace all symbols in an entry with their correct values The entry contents is updated so that values for referenced symbols will be @@ -223,7 +247,10 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False): entry entry: Entry to process section: Section which can be used to lookup symbol values + base_sym: Base symbol marking the start of the image """ + if not base_sym: + base_sym = '__image_copy_start' fname = tools.get_input_filename(elf_fname) syms = GetSymbols(fname, ['image', 'binman']) if is_elf: @@ -243,7 +270,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False): if not syms: tout.debug('LookupAndWriteSymbols: no syms') return - base = syms.get('__image_copy_start') + base = syms.get(base_sym) if not base and not is_elf: tout.debug('LookupAndWriteSymbols: no base') return @@ -518,3 +545,18 @@ def read_loadable_segments(data): rend = start + segment['p_filesz'] segments.append((i, segment['p_paddr'], data[start:rend])) return segments, entry + +def is_valid(data): + """Check if some binary data is a valid ELF file + + Args: + data (bytes): Bytes to check + + Returns: + bool: True if a valid Elf file, False if not + """ + try: + DecodeElf(data, 0) + return True + except ELFError: + return False 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 @@ class TestElf(unittest.TestCase): finally: elf.ELF_TOOLS = old_val + def test_is_valid(self): + """Test is_valid()""" + self.assertEqual(False, elf.is_valid(b'')) + self.assertEqual(False, elf.is_valid(b'1234')) + + fname = self.ElfTestFile('elf_sections') + data = tools.read_file(fname) + self.assertEqual(True, elf.is_valid(data)) + self.assertEqual(False, elf.is_valid(data[4:])) + if __name__ == '__main__': unittest.main() 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,9 +216,9 @@ This is a blob containing a device tree. The contents of the blob are obtained from the list of available device-tree files, managed by the 'state' module. -Additional Properties / Entry arguments: - - prepend: Header type to use: - length: 32-bit length header +Additional attributes: + prepend: Header used (e.g. 'length') + .. _etype_blob_ext: @@ -1178,11 +1178,13 @@ Properties / Entry arguments: - multiple-data-files: boolean to tell binman to pass all files as datafiles to mkimage instead of creating a temporary file the result of datafiles concatenation + - filename: filename of output binary generated by mkimage The data passed to mkimage via the -d flag is collected from subnodes of the mkimage node, e.g.:: mkimage { + filename = "imximage.bin"; args = "-n test -T imximage"; u-boot-spl { @@ -1190,13 +1192,14 @@ mkimage node, e.g.:: }; This calls mkimage to create an imximage with `u-boot-spl.bin` as the data -file, which mkimage being called like this:: +file, with mkimage being called like this:: mkimage -d <data_file> -n test -T imximage <output_file> The output from mkimage then becomes part of the image produced by -binman. If you need to put mulitple things in the data file, you can use -a section, or just multiple subnodes like this:: +binman but also is written into `imximage.bin` file. If you need to put +multiple things in the data file, you can use a section, or just multiple +subnodes like this:: mkimage { args = "-n test -T imximage"; @@ -1208,17 +1211,20 @@ a section, or just multiple subnodes like this:: }; }; +Note that binman places the contents (here SPL and TPL) into a single file +and passes that to mkimage using the -d option. + To pass all datafiles untouched to mkimage:: mkimage { - args = "-n rk3399 -T rkspi"; - multiple-data-files; + args = "-n rk3399 -T rkspi"; + multiple-data-files; - u-boot-tpl { - }; + u-boot-tpl { + }; - u-boot-spl { - }; + u-boot-spl { + }; }; This calls mkimage to create a Rockchip RK3399-specific first stage @@ -1242,17 +1248,17 @@ the 'data-to-imagename' property:: mkimage { args = "-T imximage"; - data-to-imagename'; + data-to-imagename; u-boot-spl { }; }; That will pass the data to mkimage both as the data file (with -d) and as -the image name (with -n). +the image name (with -n). In both cases, a filename is passed as the +argument, with the actual data being in that file. - -If need to pass different data in with -n, then use an imagename subnode:: +If need to pass different data in with -n, then use an `imagename` subnode:: mkimage { args = "-T imximage"; @@ -1271,6 +1277,20 @@ This will pass in u-boot-spl as the input data and the .cfgout file as the -n data. + +.. _etype_null: + +Entry: null: An entry which has no contents of its own +------------------------------------------------------ + +Note that the size property must be set since otherwise this entry does not +know how large it should be. + +The contents are set by the containing section, e.g. the section's pad +byte. + + + .. _etype_opensbi: Entry: opensbi: RISC-V OpenSBI fw_dynamic blob @@ -1478,6 +1498,10 @@ skip-at-start be written at offset 4 in the image file, since the first 16 bytes are skipped when writing. +filename + filename to write the unpadded section contents to within the output + directory (None to skip this). + Since a section is also an entry, it inherits all the properies of entries too. @@ -1497,12 +1521,47 @@ Entry: tee-os: Entry containing an OP-TEE Trusted OS (TEE) blob Properties / Entry arguments: - tee-os-path: Filename of file to read into entry. This is typically - called tee-pager.bin + called tee.bin or tee.elf This entry holds the run-time firmware, typically started by U-Boot SPL. See the U-Boot README for your architecture or board for how to use it. See https://github.com/OP-TEE/optee_os for more information about OP-TEE. +Note that if the file is in ELF format, it must go in a FIT. In that case, +this entry will mark itself as absent, providing the data only through the +read_elf_segments() method. + +Marking this entry as absent means that it if is used in the wrong context +it can be automatically dropped. Thus it is possible to add an OP-TEE entry +like this:: + + binman { + tee-os { + }; + }; + +and pass either an ELF or plain binary in with -a tee-os-path <filename> +and have binman do the right thing: + + - include the entry if tee.bin is provided and it does NOT have the v1 + header + - drop it otherwise + +When used within a FIT, we can do:: + + binman { + fit { + tee-os { + }; + }; + }; + +which will split the ELF into separate nodes for each segment, if an ELF +file is provided (see :ref:`etype_fit`), or produce a single node if the +OP-TEE binary v1 format is provided (see optee_doc_) . + +.. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary + .. _etype_text: @@ -1567,11 +1626,7 @@ This is the U-Boot binary, containing relocation information to allow it to relocate itself at runtime. The binary typically includes a device tree blob at the end of it. -U-Boot can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (fdt)' - -in the binman README for more information. +U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`. Note that this entry is automatically replaced with u-boot-expanded unless --no-expanded is used or the node has a 'no-expanded' property. @@ -1701,9 +1756,7 @@ not relocatable so must be loaded to the correct address in SRAM, or written to run from the correct address if direct flash execution is possible (e.g. on x86 devices). -SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' +SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. @@ -1806,9 +1859,7 @@ entry after this one, or use a u-boot-spl entry instead' which normally expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and u-boot-spl-dtb -SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' +SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. @@ -1844,9 +1895,7 @@ loader. Note that SPL is not relocatable so must be loaded to the correct address in SRAM, or written to run from the correct address if direct flash execution is possible (e.g. on x86 devices). -SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' +SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. @@ -1961,9 +2010,7 @@ entry after this one, or use a u-boot-tpl entry instead, which normally expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and u-boot-tpl-dtb -TPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' +TPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. @@ -2034,6 +2081,128 @@ Entry types that have a part to play in handling microcode: +.. _etype_u_boot_vpl: + +Entry: u-boot-vpl: U-Boot VPL binary +------------------------------------ + +Properties / Entry arguments: + - filename: Filename of u-boot-vpl.bin (default 'vpl/u-boot-vpl.bin') + +This is the U-Boot VPL (Verifying Program Loader) binary. This is a small +binary which loads before SPL, typically into on-chip SRAM. It is +responsible for locating, loading and jumping to SPL, the next-stage +loader. Note that VPL is not relocatable so must be loaded to the correct +address in SRAM, or written to run from the correct address if direct +flash execution is possible (e.g. on x86 devices). + +SPL can access binman symbols at runtime. See :ref:`binman_fdt`. + +in the binman README for more information. + +The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since +binman uses that to look up symbols to write into the VPL binary. + + + +.. _etype_u_boot_vpl_bss_pad: + +Entry: u-boot-vpl-bss-pad: U-Boot VPL binary padded with a BSS region +--------------------------------------------------------------------- + +Properties / Entry arguments: + None + +This holds the padding added after the VPL binary to cover the BSS (Block +Started by Symbol) region. This region holds the various variables used by +VPL. It is set to 0 by VPL when it starts up. If you want to append data to +the VPL image (such as a device tree file), you must pad out the BSS region +to avoid the data overlapping with U-Boot variables. This entry is useful in +that case. It automatically pads out the entry size to cover both the code, +data and BSS. + +The contents of this entry will a certain number of zero bytes, determined +by __bss_size + +The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since +binman uses that to look up the BSS address. + + + +.. _etype_u_boot_vpl_dtb: + +Entry: u-boot-vpl-dtb: U-Boot VPL device tree +--------------------------------------------- + +Properties / Entry arguments: + - filename: Filename of u-boot.dtb (default 'vpl/u-boot-vpl.dtb') + +This is the VPL device tree, containing configuration information for +VPL. VPL needs this to know what devices are present and which drivers +to activate. + + + +.. _etype_u_boot_vpl_elf: + +Entry: u-boot-vpl-elf: U-Boot VPL ELF image +------------------------------------------- + +Properties / Entry arguments: + - filename: Filename of VPL u-boot (default 'vpl/u-boot-vpl') + +This is the U-Boot VPL ELF image. It does not include a device tree but can +be relocated to any address for execution. + + + +.. _etype_u_boot_vpl_expanded: + +Entry: u-boot-vpl-expanded: U-Boot VPL flat binary broken out into its component parts +-------------------------------------------------------------------------------------- + +Properties / Entry arguments: + - vpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to + select) + +This is a section containing the U-Boot binary, BSS padding if needed and a +devicetree. Using this entry type automatically creates this section, with +the following entries in it: + + u-boot-vpl-nodtb + u-boot-vpl-bss-pad + u-boot-dtb + +Having the devicetree separate allows binman to update it in the final +image, so that the entries positions are provided to the running U-Boot. + +This entry is selected based on the value of the 'vpl-dtb' entryarg. If +this is non-empty (and not 'n' or '0') then this expanded entry is selected. + + + +.. _etype_u_boot_vpl_nodtb: + +Entry: u-boot-vpl-nodtb: VPL binary without device tree appended +---------------------------------------------------------------- + +Properties / Entry arguments: + - filename: Filename to include (default 'vpl/u-boot-vpl-nodtb.bin') + +This is the U-Boot VPL binary, It does not include a device tree blob at +the end of it so may not be able to work without it, assuming VPL needs +a device tree to operate on your platform. You can add a u_boot_vpl_dtb +entry after this one, or use a u_boot_vpl entry instead, which normally +expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and +u-boot-vpl-dtb + +VPL can access binman symbols at runtime. See :ref:`binman_fdt`. + +The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since +binman uses that to look up symbols to write into the VPL binary. + + + .. _etype_u_boot_with_ucode_ptr: Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer 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 @@ class Entry(object): compress: Compression algoithm used (e.g. 'lz4'), 'none' if none orig_offset: Original offset value read from node orig_size: Original size value read from node - missing: True if this entry is missing its contents + missing: True if this entry is missing its contents. Note that if it is + optional, this entry will not appear in the list generated by + entry.CheckMissing() since it is considered OK for it to be missing. allow_missing: Allow children of this entry to be missing (used by subclasses such as Entry_section) allow_fake: Allow creating a dummy fake file if the blob file is not @@ -91,6 +93,12 @@ class Entry(object): file, or is a binary file produced from an ELF file auto_write_symbols (bool): True to write ELF symbols into this entry's contents + absent (bool): True if this entry is absent. This can be controlled by + the entry itself, allowing it to vanish in certain circumstances. + An absent entry is removed during processing so that it does not + appear in the map + optional (bool): True if this entry contains an optional external blob + overlap (bool): True if this entry overlaps with others """ fake_dir = None @@ -133,6 +141,11 @@ class Entry(object): self.comp_bintool = None self.elf_fname = None self.auto_write_symbols = auto_write_symbols + self.absent = False + self.optional = False + self.overlap = False + self.elf_base_sym = None + self.offset_from_elf = None @staticmethod def FindEntryClass(etype, expanded): @@ -284,9 +297,15 @@ class Entry(object): self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset') self.extend_size = fdt_util.GetBool(self._node, 'extend-size') self.missing_msg = fdt_util.GetString(self._node, 'missing-msg') + self.optional = fdt_util.GetBool(self._node, 'optional') + self.overlap = fdt_util.GetBool(self._node, 'overlap') + if self.overlap: + self.required_props += ['offset', 'size'] # This is only supported by blobs and sections at present self.compress = fdt_util.GetString(self._node, 'compress', 'none') + self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node, + 'offset-from-elf') def GetDefaultFilename(self): return None @@ -444,7 +463,7 @@ class Entry(object): Returns: True if the contents were found, False if another call is needed - after the other entries are processed. + after the other entries are processed, None if there is no contents """ # No contents by default: subclasses can implement this return True @@ -483,7 +502,10 @@ class Entry(object): if self.offset_unset: self.Raise('No offset set with offset-unset: should another ' 'entry provide this correct offset?') - self.offset = tools.align(offset, self.align) + elif self.offset_from_elf: + self.offset = self.lookup_offset() + else: + self.offset = tools.align(offset, self.align) needed = self.pad_before + self.contents_size + self.pad_after needed = tools.align(needed, self.align_size) size = self.size @@ -572,7 +594,9 @@ class Entry(object): Returns: bytes content of the entry, excluding any padding. If the entry is - compressed, the compressed data is returned + compressed, the compressed data is returned. If the entry data + is not yet available, False can be returned. If the entry data + is null, then None is returned. """ self.Detail('GetData: size %s' % to_hex_size(self.data)) return self.data @@ -659,7 +683,7 @@ class Entry(object): # Check if we are writing symbols into an ELF file is_elf = self.GetDefaultFilename() == self.elf_fname elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(), - is_elf) + is_elf, self.elf_base_sym) def CheckEntries(self): """Check that the entry offsets are correct @@ -1034,14 +1058,15 @@ features to produce new behaviours. self.allow_fake = allow_fake def CheckMissing(self, missing_list): - """Check if any entries in this section have missing external blobs + """Check if the entry has missing external blobs - If there are missing blobs, the entries are added to the list + If there are missing (non-optional) blobs, the entries are added to the + list Args: missing_list: List of Entry objects to be added to """ - if self.missing: + if self.missing and not self.optional: missing_list.append(self) def check_fake_fname(self, fname, size=0): @@ -1080,6 +1105,17 @@ features to produce new behaviours. # This is meaningless for anything other than blobs pass + def CheckOptional(self, optional_list): + """Check if the entry has missing but optional external blobs + + If there are missing (optional) blobs, the entries are added to the list + + Args: + optional_list (list): List of Entry objects to be added to + """ + if self.missing and self.optional: + optional_list.append(self) + def GetAllowMissing(self): """Get whether a section allows missing external blobs @@ -1281,3 +1317,31 @@ features to produce new behaviours. not_present.append(prop) if not_present: self.Raise(f"'{self.etype}' entry is missing properties: {' '.join(not_present)}") + + def mark_absent(self, msg): + tout.info("Entry '%s' marked absent: %s" % (self._node.path, msg)) + self.absent = True + + def read_elf_segments(self): + """Read segments from an entry that can generate an ELF file + + Returns: + tuple: + list of segments, each: + int: Segment number (0 = first) + int: Start address of segment in memory + bytes: Contents of segment + int: entry address of ELF file + """ + return None + + def lookup_offset(self): + node, sym_name, offset = self.offset_from_elf + entry = self.section.FindEntryByNode(node) + if not entry: + self.Raise("Cannot find entry for node '%s'" % node.name) + if not entry.elf_fname: + entry.Raise("Need elf-fname property '%s'" % node.name) + val = elf.GetSymbolOffset(entry.elf_fname, sym_name, + entry.elf_base_sym) + return val + offset 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 @@ class Entry__testing(Entry): 'bad-update-contents-twice') self.return_contents_later = fdt_util.GetBool(self._node, 'return-contents-later') + self.set_to_absent = fdt_util.GetBool(self._node, 'set-to-absent') # Set to True when the entry is ready to process the FDT. self.process_fdt_ready = False @@ -119,6 +120,8 @@ class Entry__testing(Entry): if self.require_bintool_for_contents: if self.bintool_for_contents is None: self.Raise("Required bintool unusable in ObtainContents()") + if self.set_to_absent: + self.mark_absent('for testing purposes') return True def GetOffsets(self): 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 @@ class Entry_blob(Entry): super().__init__(section, etype, node, auto_write_symbols=auto_write_symbols) self._filename = fdt_util.GetString(self._node, 'filename', self.etype) + self.elf_fname = fdt_util.GetString(self._node, 'elf-filename', + self.elf_fname) + self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym') + if not self.auto_write_symbols: + if fdt_util.GetBool(self._node, 'write-symbols'): + self.auto_write_symbols = True def ObtainContents(self, fake_size=0): self._filename = self.GetDefaultFilename() self._pathname = tools.get_input_filename(self._filename, - self.external and self.section.GetAllowMissing()) + self.external and (self.optional or self.section.GetAllowMissing())) # Allow the file to be missing if not self._pathname: self._pathname, faked = self.check_fake_fname(self._filename, 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 @@ class Entry_fit(Entry_section): _add_entries(self._node, 0, self._node) - # Keep a copy of all entries, including generator entries, since these - # removed from self._entries later. + # Keep a copy of all entries, including generator entries, since those + # are removed from self._entries later. self._priv_entries = dict(self._entries) def BuildSectionData(self, required): @@ -540,50 +540,50 @@ class Entry_fit(Entry_section): else: self.Raise("Generator node requires 'fit,fdt-list' property") - def _gen_split_elf(base_node, node, elf_data, missing): + def _gen_split_elf(base_node, node, segments, entry_addr): """Add nodes for the ELF file, one per group of contiguous segments Args: base_node (Node): Template node from the binman definition node (Node): Node to replace (in the FIT being built) - data (bytes): ELF-format data to process (may be empty) - missing (bool): True if any of the data is missing - + segments (list): list of segments, each: + int: Segment number (0 = first) + int: Start address of segment in memory + bytes: Contents of segment + entry_addr (int): entry address of ELF file """ - # If any pieces are missing, skip this. The missing entries will - # show an error - if not missing: - try: - segments, entry = elf.read_loadable_segments(elf_data) - except ValueError as exc: - self._raise_subnode(node, - f'Failed to read ELF file: {str(exc)}') - for (seq, start, data) in segments: - node_name = node.name[1:].replace('SEQ', str(seq + 1)) - with fsw.add_node(node_name): - loadables.append(node_name) - for pname, prop in node.props.items(): - if not pname.startswith('fit,'): - fsw.property(pname, prop.bytes) - elif pname == 'fit,load': - fsw.property_u32('load', start) - elif pname == 'fit,entry': - if seq == 0: - fsw.property_u32('entry', entry) - elif pname == 'fit,data': - fsw.property('data', bytes(data)) - elif pname != 'fit,operation': - self._raise_subnode( - node, f"Unknown directive '{pname}'") + for (seq, start, data) in segments: + node_name = node.name[1:].replace('SEQ', str(seq + 1)) + with fsw.add_node(node_name): + loadables.append(node_name) + for pname, prop in node.props.items(): + if not pname.startswith('fit,'): + fsw.property(pname, prop.bytes) + elif pname == 'fit,load': + fsw.property_u32('load', start) + elif pname == 'fit,entry': + if seq == 0: + fsw.property_u32('entry', entry_addr) + elif pname == 'fit,data': + fsw.property('data', bytes(data)) + elif pname != 'fit,operation': + self._raise_subnode( + node, f"Unknown directive '{pname}'") def _gen_node(base_node, node, depth, in_images, entry): """Generate nodes from a template - This creates one node for each member of self._fdts using the - provided template. If a property value contains 'NAME' it is - replaced with the filename of the FDT. If a property value contains - SEQ it is replaced with the node sequence number, where 1 is the - first. + This creates one or more nodes depending on the fit,operation being + used. + + For OP_GEN_FDT_NODES it creates one node for each member of + self._fdts using the provided template. If a property value contains + 'NAME' it is replaced with the filename of the FDT. If a property + value contains SEQ it is replaced with the node sequence number, + where 1 is the first. + + For OP_SPLIT_ELF it emits one node for each section in the ELF file. + If the file is missing, nothing is generated. Args: base_node (Node): Base Node of the FIT (with 'description' @@ -592,6 +592,8 @@ class Entry_fit(Entry_section): depth (int): Current node depth (0 is the base 'fit' node) in_images (bool): True if this is inside the 'images' node, so that 'data' properties should be generated + entry (entry_Section): Entry for the section containing the + contents of this node """ oper = self._get_operation(base_node, node) if oper == OP_GEN_FDT_NODES: @@ -600,13 +602,28 @@ class Entry_fit(Entry_section): # Entry_section.ObtainContents() either returns True or # raises an exception. data = None - missing_list = [] + missing_opt_list = [] entry.ObtainContents() entry.Pack(0) - data = entry.GetData() - entry.CheckMissing(missing_list) + entry.CheckMissing(missing_opt_list) + entry.CheckOptional(missing_opt_list) + + # 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, data, bool(missing_list)) + _gen_split_elf(base_node, node, segments, entry_addr) def _add_node(base_node, depth, node): """Add nodes to the output FIT @@ -638,8 +655,7 @@ class Entry_fit(Entry_section): for subnode in node.subnodes: subnode_path = f'{rel_path}/{subnode.name}' - if has_images and not (subnode.name.startswith('hash') or - subnode.name.startswith('signature')): + if has_images and not self.IsSpecialSubnode(subnode): # This subnode is a content node not meant to appear in # the FIT (e.g. "/images/kernel/u-boot"), so don't call # fsw.add_node() or _add_node() for it. 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 @@ class Entry_mkimage(Entry): Note that binman places the contents (here SPL and TPL) into a single file and passes that to mkimage using the -d option. - To pass all datafiles untouched to mkimage:: + To pass all datafiles untouched to mkimage:: - mkimage { - args = "-n rk3399 -T rkspi"; - multiple-data-files; + mkimage { + args = "-n rk3399 -T rkspi"; + multiple-data-files; - u-boot-tpl { - }; + u-boot-tpl { + }; - u-boot-spl { - }; - }; + u-boot-spl { + }; + }; - This calls mkimage to create a Rockchip RK3399-specific first stage - bootloader, made of TPL+SPL. Since this first stage bootloader requires to - align the TPL and SPL but also some weird hacks that is handled by mkimage - directly, binman is told to not perform the concatenation of datafiles prior - to passing the data to mkimage. + This calls mkimage to create a Rockchip RK3399-specific first stage + bootloader, made of TPL+SPL. Since this first stage bootloader requires to + align the TPL and SPL but also some weird hacks that is handled by mkimage + directly, binman is told to not perform the concatenation of datafiles prior + to passing the data to mkimage. To use CONFIG options in the arguments, use a string list instead, as in this example which also produces four arguments:: 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 @@ class Entry_section(Entry): be written at offset 4 in the image file, since the first 16 bytes are skipped when writing. + filename + filename to write the unpadded section contents to within the output + directory (None to skip this). + Since a section is also an entry, it inherits all the properies of entries too. @@ -163,6 +167,18 @@ class Entry_section(Entry): self._skip_at_start = None self._end_4gb = False self._ignore_missing = False + self._filename = None + + def IsSpecialSubnode(self, node): + """Check if a node is a special one used by the section itself + + Some notes are used for hashing / signatures and do not add entries to + the actual section. + + Returns: + bool: True if the node is a special one, else False + """ + return node.name.startswith('hash') or node.name.startswith('signature') def ReadNode(self): """Read properties from the section node""" @@ -183,12 +199,14 @@ class Entry_section(Entry): self._skip_at_start = 0 self._name_prefix = fdt_util.GetString(self._node, 'name-prefix') self.align_default = fdt_util.GetInt(self._node, 'align-default', 0) + self._filename = fdt_util.GetString(self._node, 'filename', + self._filename) self.ReadEntries() def ReadEntries(self): for node in self._node.subnodes: - if node.name.startswith('hash') or node.name.startswith('signature'): + if self.IsSpecialSubnode(node): continue entry = Entry.Create(self, node, expanded=self.GetImage().use_expanded, @@ -258,6 +276,7 @@ class Entry_section(Entry): Args: entry: Entry to check + entry_data: Data for the entry, False if is null Returns: Contents of the entry along with any pad bytes before and @@ -312,14 +331,32 @@ class Entry_section(Entry): # earlier in the image description. See testCollectionSection(). if not required and entry_data is None: return None - data = self.GetPaddedDataForEntry(entry, entry_data) + + entry_data_final = entry_data + if entry_data is None: + pad_byte = (entry._pad_byte if isinstance(entry, Entry_section) + else self._pad_byte) + entry_data_final = tools.get_bytes(self._pad_byte, entry.size) + + data = self.GetPaddedDataForEntry(entry, entry_data_final) # Handle empty space before the entry pad = (entry.offset or 0) - self._skip_at_start - len(section_data) if pad > 0: section_data += tools.get_bytes(self._pad_byte, pad) # Add in the actual entry data - section_data += data + if entry.overlap: + end_offset = entry.offset + entry.size + if end_offset > len(section_data): + entry.Raise("Offset %#x (%d) ending at %#x (%d) must overlap with existing entries" % + (entry.offset, entry.offset, end_offset, + end_offset)) + # Don't write anything for null entries' + if entry_data is not None: + section_data = (section_data[:entry.offset] + data + + section_data[entry.offset + entry.size:]) + else: + section_data += data self.Detail('GetData: %d entries, total size %#x' % (len(self._entries), len(section_data))) @@ -348,7 +385,8 @@ class Entry_section(Entry): """Get the contents of an entry This builds the contents of the section, stores this as the contents of - the section and returns it + the section and returns it. If the section has a filename, the data is + written there also. Args: required: True if the data must be present, False if it is OK to @@ -363,6 +401,8 @@ class Entry_section(Entry): if data is None: return None self.SetContents(data) + if self._filename: + tools.write_file(tools.get_output_filename(self._filename), data) return data def GetOffsets(self): @@ -439,12 +479,13 @@ class Entry_section(Entry): (entry.offset, entry.offset, entry.size, entry.size, self._node.path, self._skip_at_start, self._skip_at_start, max_size, max_size)) - if entry.offset < offset and entry.size: - entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' " - "ending at %#x (%d)" % - (entry.offset, entry.offset, prev_name, offset, offset)) - offset = entry.offset + entry.size - prev_name = entry.GetPath() + if not entry.overlap: + if entry.offset < offset and entry.size: + entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' ending at %#x (%d)" % + (entry.offset, entry.offset, prev_name, offset, + offset)) + offset = entry.offset + entry.size + prev_name = entry.GetPath() def WriteSymbols(self, section): """Write symbol values into binary files for access at run time""" @@ -662,10 +703,13 @@ class Entry_section(Entry): def GetEntryContents(self, skip_entry=None): """Call ObtainContents() for each entry in the section + + Note that this may set entry.absent to True if the entry is not + actually needed """ def _CheckDone(entry): if entry != skip_entry: - if not entry.ObtainContents(): + if entry.ObtainContents() is False: next_todo.append(entry) return entry @@ -706,6 +750,10 @@ class Entry_section(Entry): todo) return True + def drop_absent(self): + """Drop entries which are absent""" + self._entries = {n: e for n, e in self._entries.items() if not e.absent} + def _SetEntryOffsetSize(self, name, offset, size): """Set the offset and size of an entry @@ -846,7 +894,8 @@ class Entry_section(Entry): def CheckMissing(self, missing_list): """Check if any entries in this section have missing external blobs - If there are missing blobs, the entries are added to the list + If there are missing (non-optional) blobs, the entries are added to the + list Args: missing_list: List of Entry objects to be added to @@ -865,6 +914,17 @@ class Entry_section(Entry): for entry in self._entries.values(): entry.CheckFakedBlobs(faked_blobs_list) + def CheckOptional(self, optional_list): + """Check the section for missing but optional external blobs + + If there are missing (optional) blobs, the entries are added to the list + + Args: + optional_list (list): List of Entry objects to be added to + """ + for entry in self._entries.values(): + entry.CheckOptional(optional_list) + def check_missing_bintools(self, missing_list): """Check if any entries in this section have missing bintools @@ -931,3 +991,12 @@ class Entry_section(Entry): super().AddBintools(btools) for entry in self._entries.values(): entry.AddBintools(btools) + + def read_elf_segments(self): + entries = self.GetEntries() + + # If the section only has one entry, see if it can provide ELF segments + if len(entries) == 1: + for entry in entries.values(): + return entry.read_elf_segments() + return None 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 @@ class Entry_u_boot(Entry_blob): to relocate itself at runtime. The binary typically includes a device tree blob at the end of it. - U-Boot can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (fdt)' - - in the binman README for more information. + U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`. Note that this entry is automatically replaced with u-boot-expanded unless --no-expanded is used or the node has a 'no-expanded' property. 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 @@ class Entry_u_boot_spl(Entry_blob): to run from the correct address if direct flash execution is possible (e.g. on x86 devices). - SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' + SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. @@ -36,7 +34,6 @@ class Entry_u_boot_spl(Entry_blob): def __init__(self, section, etype, node): super().__init__(section, etype, node, auto_write_symbols=True) self.elf_fname = 'spl/u-boot-spl' - self.auto_write_symbols = True def GetDefaultFilename(self): return 'spl/u-boot-spl.bin' 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 @@ class Entry_u_boot_spl_nodtb(Entry_blob): expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and u-boot-spl-dtb - SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' + SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. 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 @@ class Entry_u_boot_tpl(Entry_blob): address in SRAM, or written to run from the correct address if direct flash execution is possible (e.g. on x86 devices). - SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' + SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. 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 @@ class Entry_u_boot_tpl_nodtb(Entry_blob): expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and u-boot-tpl-dtb - TPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' + TPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. 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 @@ class Entry_u_boot_vpl(Entry_blob): address in SRAM, or written to run from the correct address if direct flash execution is possible (e.g. on x86 devices). - SPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' + SPL can access binman symbols at runtime. See :ref:`binman_fdt`. in the binman README for more information. 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 @@ class Entry_u_boot_vpl_nodtb(Entry_blob): expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and u-boot-vpl-dtb - VPL can access binman symbols at runtime. See: - - 'Access to binman entry offsets at run time (symbols)' - - in the binman README for more information. + VPL can access binman symbols at runtime. See :ref:`binman_fdt`. The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since binman uses that to look up symbols to write into the VPL binary. 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 @@ REPACK_DTB_PROPS = ['orig-offset', 'orig-size'] # Supported compression bintools COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd'] +TEE_ADDR = 0x5678 + class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -219,6 +221,9 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('tee.elf', tools.read_file(cls.ElfTestFile('elf_sections'))) + # Newer OP_TEE file in v1 binary format + cls.make_tee_bin('tee.bin') + cls.comp_bintools = {} for name in COMP_BINTOOLS: cls.comp_bintools[name] = bintool.Bintool.create(name) @@ -644,6 +649,14 @@ class TestFunctional(unittest.TestCase): def ElfTestFile(cls, fname): return os.path.join(cls._elf_testdir, fname) + @classmethod + def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''): + init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0) + data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo, + dummy, paged_sz) + U_BOOT_DATA + data += extra_data + TestFunctional._MakeInputFile(fname, data) + def AssertInList(self, grep_list, target): """Assert that at least one of a list of things is in a target @@ -6077,5 +6090,225 @@ fdt fdtmap Extract the devicetree blob from the fdtmap 'Cannot write symbols to an ELF file without Python elftools', str(exc.exception)) + def testSectionFilename(self): + """Check writing of section contents to a file""" + data = self._DoReadFile('261_section_fname.dts') + expected = (b'&&' + U_BOOT_DATA + b'&&&' + + tools.get_bytes(ord('!'), 7) + + U_BOOT_DATA + tools.get_bytes(ord('&'), 12)) + self.assertEqual(expected, data) + + sect_fname = tools.get_output_filename('outfile.bin') + self.assertTrue(os.path.exists(sect_fname)) + sect_data = tools.read_file(sect_fname) + self.assertEqual(U_BOOT_DATA, sect_data) + + def testAbsent(self): + """Check handling of absent entries""" + data = self._DoReadFile('262_absent.dts') + self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data) + + def testPackTeeOsOptional(self): + """Test that an image with an optional TEE binary can be created""" + entry_args = { + 'tee-os-path': 'tee.elf', + } + data = self._DoReadFileDtb('263_tee_os_opt.dts', + entry_args=entry_args)[0] + self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data) + + def checkFitTee(self, dts, tee_fname): + """Check that a tee-os entry works and returns data + + Args: + dts (str): Device tree filename to use + tee_fname (str): filename containing tee-os + + Returns: + bytes: Image contents + """ + if not elf.ELF_TOOLS: + self.skipTest('Python elftools not available') + entry_args = { + 'of-list': 'test-fdt1 test-fdt2', + 'default-dt': 'test-fdt2', + 'tee-os-path': tee_fname, + } + test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR) + data = self._DoReadFileDtb(dts, entry_args=entry_args, + extra_indirs=[test_subdir])[0] + return data + + def testFitTeeOsOptionalFit(self): + """Test an image with a FIT with an optional OP-TEE binary""" + data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin') + + # There should be only one node, holding the data set up in SetUpClass() + # for tee.bin + dtb = fdt.Fdt.FromData(data) + dtb.Scan() + node = dtb.GetNode('/images/tee-1') + self.assertEqual(TEE_ADDR, + fdt_util.fdt32_to_cpu(node.props['load'].value)) + self.assertEqual(TEE_ADDR, + fdt_util.fdt32_to_cpu(node.props['entry'].value)) + self.assertEqual(U_BOOT_DATA, node.props['data'].bytes) + + def testFitTeeOsOptionalFitBad(self): + """Test an image with a FIT with an optional OP-TEE binary""" + with self.assertRaises(ValueError) as exc: + self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin') + self.assertIn( + "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match", + str(exc.exception)) + + def testFitTeeOsBad(self): + """Test an OP-TEE binary with wrong formats""" + self.make_tee_bin('tee.bad1', 123) + with self.assertRaises(ValueError) as exc: + self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1') + self.assertIn( + "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported", + str(exc.exception)) + + self.make_tee_bin('tee.bad2', 0, b'extra data') + with self.assertRaises(ValueError) as exc: + self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2') + self.assertIn( + "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)", + str(exc.exception)) + + def testExtblobOptional(self): + """Test an image with an external blob that is optional""" + with test_util.capture_sys_output() as (stdout, stderr): + data = self._DoReadFile('266_blob_ext_opt.dts') + self.assertEqual(REFCODE_DATA, data) + err = stderr.getvalue() + self.assertRegex( + err, + "Image '.*' is missing external blobs but is still functional: missing") + + def testSectionInner(self): + """Test an inner section with a size""" + data = self._DoReadFile('267_section_inner.dts') + expected = U_BOOT_DATA + tools.get_bytes(0, 12) + self.assertEqual(expected, data) + + def testNull(self): + """Test an image with a null entry""" + data = self._DoReadFile('268_null.dts') + self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data) + + def testOverlap(self): + """Test an image with a overlapping entry""" + data = self._DoReadFile('269_overlap.dts') + self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data) + + image = control.images['image'] + entries = image.GetEntries() + + self.assertIn('inset', entries) + inset = entries['inset'] + self.assertEqual(1, inset.offset); + self.assertEqual(1, inset.image_pos); + self.assertEqual(2, inset.size); + + def testOverlapNull(self): + """Test an image with a null overlap""" + data = self._DoReadFile('270_overlap_null.dts') + self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) + + # Check the FMAP + fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):]) + self.assertEqual(4, fhdr.nareas) + fiter = iter(fentries) + + fentry = next(fiter) + self.assertEqual(b'SECTION', fentry.name) + self.assertEqual(0, fentry.offset) + self.assertEqual(len(U_BOOT_DATA), fentry.size) + self.assertEqual(0, fentry.flags) + + fentry = next(fiter) + self.assertEqual(b'U_BOOT', fentry.name) + self.assertEqual(0, fentry.offset) + self.assertEqual(len(U_BOOT_DATA), fentry.size) + self.assertEqual(0, fentry.flags) + + # Make sure that the NULL entry appears in the FMAP + fentry = next(fiter) + self.assertEqual(b'NULL', fentry.name) + self.assertEqual(1, fentry.offset) + self.assertEqual(2, fentry.size) + self.assertEqual(0, fentry.flags) + + fentry = next(fiter) + self.assertEqual(b'FMAP', fentry.name) + self.assertEqual(len(U_BOOT_DATA), fentry.offset) + + def testOverlapBad(self): + """Test an image with a bad overlapping entry""" + with self.assertRaises(ValueError) as exc: + self._DoReadFile('271_overlap_bad.dts') + self.assertIn( + "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries", + str(exc.exception)) + + def testOverlapNoOffset(self): + """Test an image with a bad overlapping entry""" + with self.assertRaises(ValueError) as exc: + self._DoReadFile('272_overlap_no_size.dts') + self.assertIn( + "Node '/binman/inset': 'fill' entry is missing properties: size", + str(exc.exception)) + + def testBlobSymbol(self): + """Test a blob with symbols read from an ELF file""" + elf_fname = self.ElfTestFile('blob_syms') + TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname)) + TestFunctional._MakeInputFile('blob_syms.bin', + tools.read_file(self.ElfTestFile('blob_syms.bin'))) + + data = self._DoReadFile('273_blob_symbol.dts') + + syms = elf.GetSymbols(elf_fname, ['binman', 'image']) + addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym') + self.assertEqual(syms['_binman_sym_magic'].address, addr) + self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4) + self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8) + + sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8) + expected = sym_values + self.assertEqual(expected, data[:len(expected)]) + + def testOffsetFromElf(self): + """Test a blob with symbols read from an ELF file""" + elf_fname = self.ElfTestFile('blob_syms') + TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname)) + TestFunctional._MakeInputFile('blob_syms.bin', + tools.read_file(self.ElfTestFile('blob_syms.bin'))) + + data = self._DoReadFile('274_offset_from_elf.dts') + + syms = elf.GetSymbols(elf_fname, ['binman', 'image']) + base = elf.GetSymbolAddress(elf_fname, '__my_start_sym') + + image = control.images['image'] + entries = image.GetEntries() + + self.assertIn('inset', entries) + inset = entries['inset'] + + self.assertEqual(base + 4, inset.offset); + self.assertEqual(base + 4, inset.image_pos); + self.assertEqual(4, inset.size); + + self.assertIn('inset2', entries) + inset = entries['inset2'] + self.assertEqual(base + 8, inset.offset); + self.assertEqual(base + 8, inset.image_pos); + self.assertEqual(4, inset.size); + + if __name__ == "__main__": unittest.main() 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 @@ class Image(section.Entry_section): def ReadNode(self): super().ReadNode() - filename = fdt_util.GetString(self._node, 'filename') - if filename: - self._filename = filename self.allow_repack = fdt_util.GetBool(self._node, 'allow-repack') self._symlink = fdt_util.GetString(self._node, 'symlink') 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_BAD := -T $(SRC)u_boot_binman_syms_bad.lds LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds LDS_EFL_SECTIONS := -T $(SRC)elf_sections.lds +LDS_BLOB := -T $(SRC)blob_syms.lds TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \ - u_boot_binman_embed u_boot_binman_embed_sm elf_sections + u_boot_binman_embed u_boot_binman_embed_sm elf_sections blob_syms.bin all: $(TARGETS) @@ -71,6 +72,12 @@ u_boot_binman_embed: u_boot_binman_embed.c u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED) u_boot_binman_embed_sm: u_boot_binman_embed_sm.c +blob_syms.bin: blob_syms + $(OBJCOPY) -O binary $< -R .note.gnu.build-id $@ + +blob_syms: CFLAGS += $(LDS_BLOB) +blob_syms: blob_syms.c + elf_sections: CFLAGS += $(LDS_EFL_SECTIONS) elf_sections: elf_sections.c 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 @@ def GetPhandleList(node, propname): value = [value] return [fdt32_to_cpu(v) for v in value] +def GetPhandleNameOffset(node, propname): + """Get a <&phandle>, "string", <offset> value from a property + + Args: + node: Node object to read from + propname: property name to read + + Returns: + tuple: + Node object + str + int + or None if the property does not exist + """ + prop = node.props.get(propname) + if not prop: + return None + value = prop.bytes + phandle = fdt32_to_cpu(value[:4]) + node = node.GetFdt().LookupPhandle(phandle) + name = '' + for byte in value[4:]: + if not byte: + break + name += chr(byte) + val = fdt32_to_cpu(value[4 + len(name) + 1:]) + return node, name, val + def GetDatatype(node, propname, datatype): """Get a value of a given type from a property 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 @@ U_BOOT_DRVINFO(spl_test) = { self._check_strings(HEADER + ''' struct dtd_source { \tstruct phandle_2_arg clocks[4]; +\tunsigned char phandle_name_offset[13]; }; struct dtd_target { \tfdt32_t\t\tintval; @@ -981,6 +982,8 @@ static struct dtd_source dtv_phandle_source = { \t\t\t{0, {11}}, \t\t\t{1, {12, 13}}, \t\t\t{4, {}},}, +\t.phandle_name_offset = {0x0, 0x0, 0x0, 0x3, 0x66, 0x72, 0x65, 0x64, +\t\t0x0, 0x0, 0x0, 0x0, 0x7b}, }; U_BOOT_DRVINFO(phandle_source) = { \t.name\t\t= "source", 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 @@ class TestFdtUtil(unittest.TestCase): finally: tools.outdir= old_outdir + def test_get_phandle_name_offset(self): + val = fdt_util.GetPhandleNameOffset(self.node, 'missing') + self.assertIsNone(val) + + dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts')) + node = dtb.GetNode('/phandle-source') + node, name, offset = fdt_util.GetPhandleNameOffset(node, + 'phandle-name-offset') + self.assertEqual('phandle3-target', node.name) + self.assertEqual('fred', name) + self.assertEqual(123, offset) def run_test_coverage(build_dir): """Run the tests and check that we get 100% coverage 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 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc, tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true, false); - if (tfd < 0) + if (tfd < 0) { + fprintf(stderr, "Cannot map FDT file '%s'\n", tmpfile); return -EIO; + } if (params->keydest) { struct stat dest_sbuf; 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 @@ int fit_add_verification_data(const char *keydir, const char *keyfile, ret = fit_image_add_verification_data(keydir, keyfile, keydest, fit, noffset, comment, require_keys, engine_id, cmdname, algo_name); - if (ret) + if (ret) { + printf("Can't add verification data for node '%s' (%s)\n", + fdt_get_name(fit, noffset, NULL), + fdt_strerror(ret)); return ret; + } } /* If there are no keys, we can't sign configurations */ 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 @@ def check_patch(fname, verbose=False, show_types=False, use_tree=False): stdout: Full output of checkpatch """ chk = find_check_patch() - args = [chk, '--u-boot', '--strict'] + args = [chk] if not use_tree: args.append('--no-tree') if show_types: 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 outf(int level, const char *fmt, ...) static void usage(void) { fprintf(stderr, - "Usage: proftool -cds -v3 <cmd> <profdata>\n" + "Usage: proftool [-cmtv] <cmd> <profdata>\n" "\n" "Commands\n" " dump-ftrace\t\tDump out textual data in ftrace format\n" "\n" "Options:\n" + " -c <cfg>\tSpecific config file\n" " -m <map>\tSpecify Systen.map file\n" - " -t <trace>\tSpecific trace data file (from U-Boot)\n" + " -t <fname>\tSpecify trace data file (from U-Boot 'trace calls')\n" " -v <0-4>\tSpecify verbosity\n"); exit(EXIT_FAILURE); } @@ -162,7 +163,7 @@ static int read_data(FILE *fin, void *buff, int size) if (!err) return 1; if (err != size) { - error("Cannot read profile file at pos %ld\n", ftell(fin)); + error("Cannot read profile file at pos %lx\n", ftell(fin)); return -1; } return 0; @@ -495,10 +496,17 @@ static int make_ftrace(void) int missing_count = 0, skip_count = 0; int i; - printf("# tracer: ftrace\n" - "#\n" - "# TASK-PID CPU# TIMESTAMP FUNCTION\n" - "# | | | | |\n"); + printf("# tracer: function\n" + "#\n" + "# entries-in-buffer/entries-written: 140080/250280 #P:4\n" + "#\n" + "# _-----=> irqs-off\n" + "# / _----=> need-resched\n" + "# | / _---=> hardirq/softirq\n" + "# || / _--=> preempt-depth\n" + "# ||| / delay\n" + "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n" + "# | | | |||| | |\n"); for (i = 0, call = call_list; i < call_count; i++, call++) { struct func_info *func = find_func_by_offset(call->func); ulong time = call->flags & FUNCF_TIMESTAMP_MASK; @@ -520,7 +528,7 @@ static int make_ftrace(void) continue; } - printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1, + printf("%16s-%-5d [000] .... %lu.%06lu: ", "uboot", 1, time / 1000000, time % 1000000); out_func(call->func, 0, " <- "); @@ -562,23 +570,23 @@ static int prof_tool(int argc, char *const argv[], int main(int argc, char *argv[]) { const char *map_fname = "System.map"; - const char *prof_fname = NULL; - const char *trace_config_fname = NULL; + const char *trace_fname = NULL; + const char *config_fname = NULL; int opt; verbose = 2; - while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) { + while ((opt = getopt(argc, argv, "c:m:t:v:")) != -1) { switch (opt) { - case '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 @@ int main(int argc, char *argv[]) usage(); debug("Debug enabled\n"); - return prof_tool(argc, argv, prof_fname, map_fname, - trace_config_fname); + return prof_tool(argc, argv, trace_fname, map_fname, config_fname); } |