mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-26 04:17:09 +00:00
convert rockchip to use binman
patman fix for checkpatch binman optional entries, improved support for ELF symbols trace improvements minor fdt refactoring -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmPIpV4RHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIreZuqwgA0UpYQEX6/MegzHSCIx3AMT4rCF1Ytitr LS4Cbvj1Q09Rt9jriW7wAV5AobVPwGf2L5SVcnWv2I9+MmypDIXEe8HIrt2fRFu9 bzn/2GOzXczuXqPFa/CWOUwjvCzTb8Sl9NtRszrP5NvOzuN15x00ZUYaXFO7fgsB zZMzOKxemwjdtLaox+x+VIJ95HMDEkYrWTAqTPg74CNVSjRbbLNqNq0zqkHB8SnH ubgphtIKYItTeIXcfIa9V4LeQp0ZitkzSfAibX+nIPCMPg9jbG9MrQQ+VvSZDjnM y8wa8gFj47Ek+gGNFXMHIpO6tBd83uHRgtf2x+zhcovLELYnZ6fDGw== =1K6m -----END PGP SIGNATURE----- Merge tag 'dm-pull-18jan23' of https://source.denx.de/u-boot/custodians/u-boot-dm convert rockchip to use binman patman fix for checkpatch binman optional entries, improved support for ELF symbols trace improvements minor fdt refactoring
This commit is contained in:
commit
53c47c59e6
78 changed files with 1617 additions and 537 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@
|
||||||
# Normal rules (sorted alphabetically)
|
# Normal rules (sorted alphabetically)
|
||||||
#
|
#
|
||||||
.*
|
.*
|
||||||
|
!.checkpatch.conf
|
||||||
*.a
|
*.a
|
||||||
*.asn1.[ch]
|
*.asn1.[ch]
|
||||||
*.bin
|
*.bin
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -1006,14 +1006,9 @@ ifeq ($(CONFIG_INIT_SP_RELATIVE)$(CONFIG_OF_SEPARATE),yy)
|
||||||
INPUTS-y += init_sp_bss_offset_check
|
INPUTS-y += init_sp_bss_offset_check
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_ARCH_ROCKCHIP)$(CONFIG_SPL),yy)
|
ifeq ($(CONFIG_ARCH_ROCKCHIP)_$(CONFIG_SPL_FRAMEWORK),y_)
|
||||||
# Binman image dependencies
|
|
||||||
ifeq ($(CONFIG_ARM64),y)
|
|
||||||
INPUTS-y += u-boot.itb
|
|
||||||
else
|
|
||||||
INPUTS-y += u-boot.img
|
INPUTS-y += u-boot.img
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
|
|
||||||
INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \
|
INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \
|
||||||
$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.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
|
else
|
||||||
ifneq ($(CONFIG_USE_SPL_FIT_GENERATOR),)
|
ifneq ($(CONFIG_USE_SPL_FIT_GENERATOR),)
|
||||||
U_BOOT_ITS := u-boot.its
|
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
|
$(U_BOOT_ITS): $(U_BOOT_ITS_DEPS) FORCE
|
||||||
$(srctree)/$(CONFIG_SPL_FIT_GENERATOR) \
|
$(srctree)/$(CONFIG_SPL_FIT_GENERATOR) \
|
||||||
$(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) > $@
|
$(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
|
u-boot-with-spl.bin: $(SPL_IMAGE) $(SPL_PAYLOAD) FORCE
|
||||||
$(call if_changed,pad_cat)
|
$(call if_changed,pad_cat)
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy)
|
ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy)
|
||||||
MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE)
|
MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE)
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ unsigned long get_timer(unsigned long base)
|
||||||
return time_ms - 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;
|
static unsigned long base_time_us;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||||
/*
|
/*
|
||||||
* Generic timer implementation of get_tbclk()
|
* Generic timer implementation of get_tbclk()
|
||||||
*/
|
*/
|
||||||
unsigned long get_tbclk(void)
|
unsigned long notrace get_tbclk(void)
|
||||||
{
|
{
|
||||||
unsigned long cntfrq;
|
unsigned long cntfrq;
|
||||||
asm volatile("mrs %0, cntfrq_el0" : "=r" (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).
|
* 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;
|
unsigned long cntpct;
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ unsigned long timer_read_counter(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint64_t get_ticks(void)
|
uint64_t notrace get_ticks(void)
|
||||||
{
|
{
|
||||||
unsigned long ticks = timer_read_counter();
|
unsigned long ticks = timer_read_counter();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
&binman {
|
&binman {
|
||||||
simple-bin {
|
simple-bin {
|
||||||
blob {
|
fit {
|
||||||
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
|
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,14 +46,14 @@
|
||||||
|
|
||||||
&binman {
|
&binman {
|
||||||
simple-bin {
|
simple-bin {
|
||||||
blob {
|
fit {
|
||||||
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
|
offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ROCKCHIP_SPI_IMAGE
|
#ifdef CONFIG_ROCKCHIP_SPI_IMAGE
|
||||||
simple-bin-spi {
|
simple-bin-spi {
|
||||||
blob {
|
fit {
|
||||||
/* same as u-boot,spl-payload-offset */
|
/* same as u-boot,spl-payload-offset */
|
||||||
offset = <0x80000>;
|
offset = <0x80000>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
|
|
||||||
#if defined(CONFIG_ROCKCHIP_SPI_IMAGE) && defined(CONFIG_HAS_ROM)
|
#if defined(CONFIG_ROCKCHIP_SPI_IMAGE) && defined(CONFIG_HAS_ROM)
|
||||||
&binman {
|
&binman {
|
||||||
|
multiple-images;
|
||||||
rom {
|
rom {
|
||||||
filename = "u-boot.rom";
|
filename = "u-boot.rom";
|
||||||
size = <0x400000>;
|
size = <0x400000>;
|
||||||
|
@ -82,7 +83,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#endif
|
#endif /* CONFIG_ROCKCHIP_SPI_IMAGE && CONFIG_HAS_ROM */
|
||||||
|
|
||||||
&cru {
|
&cru {
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-reloc;
|
||||||
|
|
|
@ -30,14 +30,79 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ARM64
|
#if defined(CONFIG_SPL_FIT) && defined(CONFIG_ARM64)
|
||||||
blob {
|
fit: fit {
|
||||||
|
description = "FIT image for U-Boot with bl31 (TF-A)";
|
||||||
|
#address-cells = <1>;
|
||||||
|
fit,fdt-list = "of-list";
|
||||||
filename = "u-boot.itb";
|
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
|
#else
|
||||||
u-boot-img {
|
u-boot-img {
|
||||||
#endif
|
|
||||||
offset = <CONFIG_SPL_PAD_TO>;
|
offset = <CONFIG_SPL_PAD_TO>;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ROCKCHIP_SPI_IMAGE
|
#ifdef CONFIG_ROCKCHIP_SPI_IMAGE
|
||||||
|
@ -59,7 +124,8 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ARM64
|
#ifdef CONFIG_ARM64
|
||||||
blob {
|
fit {
|
||||||
|
type = "blob";
|
||||||
filename = "u-boot.itb";
|
filename = "u-boot.itb";
|
||||||
#else
|
#else
|
||||||
u-boot-img {
|
u-boot-img {
|
||||||
|
@ -68,6 +134,6 @@
|
||||||
offset = <CONFIG_SYS_SPI_U_BOOT_OFFS>;
|
offset = <CONFIG_SYS_SPI_U_BOOT_OFFS>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#endif
|
#endif /* CONFIG_ROCKCHIP_SPI_IMAGE */
|
||||||
};
|
};
|
||||||
#endif
|
#endif /* CONFIG_SPL */
|
||||||
|
|
|
@ -248,7 +248,7 @@ static inline char *s5p_get_cpu_name(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IS_SAMSUNG_TYPE(type, id) \
|
#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; \
|
return (s5p_cpu_id >> 12) == id; \
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ IS_SAMSUNG_TYPE(exynos4, 0x4)
|
||||||
IS_SAMSUNG_TYPE(exynos5, 0x5)
|
IS_SAMSUNG_TYPE(exynos5, 0x5)
|
||||||
|
|
||||||
#define IS_EXYNOS_TYPE(type, id) \
|
#define IS_EXYNOS_TYPE(type, id) \
|
||||||
static inline int __attribute__((no_instrument_function)) \
|
static inline int notrace \
|
||||||
proid_is_##type(void) \
|
proid_is_##type(void) \
|
||||||
{ \
|
{ \
|
||||||
return s5p_cpu_id == id; \
|
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 proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422())
|
||||||
|
|
||||||
#define SAMSUNG_BASE(device, base) \
|
#define SAMSUNG_BASE(device, base) \
|
||||||
static inline unsigned long __attribute__((no_instrument_function)) \
|
static inline unsigned long notrace \
|
||||||
samsung_get_base_##device(void) \
|
samsung_get_base_##device(void) \
|
||||||
{ \
|
{ \
|
||||||
if (cpu_is_exynos4()) { \
|
if (cpu_is_exynos4()) { \
|
||||||
|
|
|
@ -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()
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <bootstage.h>
|
||||||
#include <debug_uart.h>
|
#include <debug_uart.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <hang.h>
|
#include <hang.h>
|
||||||
|
@ -70,15 +71,15 @@ void board_init_f(ulong dummy)
|
||||||
U_BOOT_TIME ")\n");
|
U_BOOT_TIME ")\n");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
/* Init secure timer */
|
||||||
|
rockchip_stimer_init();
|
||||||
|
|
||||||
ret = spl_early_init();
|
ret = spl_early_init();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
debug("spl_early_init() failed: %d\n", ret);
|
debug("spl_early_init() failed: %d\n", ret);
|
||||||
hang();
|
hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init secure timer */
|
|
||||||
rockchip_stimer_init();
|
|
||||||
|
|
||||||
/* Init ARM arch timer */
|
/* Init ARM arch timer */
|
||||||
if (IS_ENABLED(CONFIG_SYS_ARCH_TIMER))
|
if (IS_ENABLED(CONFIG_SYS_ARCH_TIMER))
|
||||||
timer_init();
|
timer_init();
|
||||||
|
@ -93,6 +94,15 @@ void board_init_f(ulong dummy)
|
||||||
int board_return_to_bootrom(struct spl_image_info *spl_image,
|
int board_return_to_bootrom(struct spl_image_info *spl_image,
|
||||||
struct spl_boot_device *bootdev)
|
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);
|
back_to_bootrom(BROM_BOOT_NEXTSTAGE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -137,7 +137,7 @@ struct arch_global_data {
|
||||||
|
|
||||||
#define DECLARE_GLOBAL_DATA_PTR extern struct global_data *global_data_ptr
|
#define DECLARE_GLOBAL_DATA_PTR extern struct global_data *global_data_ptr
|
||||||
# else
|
# 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;
|
gd_t *gd_ptr;
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
|
||||||
#define EAX_EDX_RET(val, low, high) "=A" (val)
|
#define EAX_EDX_RET(val, low, high) "=A" (val)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline __attribute__((no_instrument_function))
|
static inline notrace
|
||||||
unsigned long long native_read_msr(unsigned int msr)
|
unsigned long long native_read_msr(unsigned int msr)
|
||||||
{
|
{
|
||||||
DECLARE_ARGS(val, low, high);
|
DECLARE_ARGS(val, low, high);
|
||||||
|
|
|
@ -108,7 +108,7 @@ void board_init_f_r(void) __attribute__ ((noreturn));
|
||||||
int arch_misc_init(void);
|
int arch_misc_init(void);
|
||||||
|
|
||||||
/* Read the time stamp counter */
|
/* 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;
|
uint32_t high, low;
|
||||||
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
|
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
|
||||||
|
|
|
@ -282,12 +282,11 @@ config SPL_FIT_SOURCE
|
||||||
config USE_SPL_FIT_GENERATOR
|
config USE_SPL_FIT_GENERATOR
|
||||||
bool "Use a script to generate the .its script"
|
bool "Use a script to generate the .its script"
|
||||||
depends on SPL_FIT
|
depends on SPL_FIT
|
||||||
default y if !ARCH_SUNXI && !RISCV
|
default y if SPL_FIT && ARCH_ZYNQMP
|
||||||
|
|
||||||
config SPL_FIT_GENERATOR
|
config SPL_FIT_GENERATOR
|
||||||
string ".its file generator script for U-Boot FIT image"
|
string ".its file generator script for U-Boot FIT image"
|
||||||
depends on USE_SPL_FIT_GENERATOR
|
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
|
default "arch/arm/mach-zynqmp/mkimage_fit_atf.sh" if SPL_LOAD_FIT && ARCH_ZYNQMP
|
||||||
help
|
help
|
||||||
Specifies a (platform specific) script file to generate the FIT
|
Specifies a (platform specific) script file to generate the FIT
|
||||||
|
|
|
@ -599,6 +599,7 @@ static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
|
||||||
debug("Ignoring compatible = %s property\n",
|
debug("Ignoring compatible = %s property\n",
|
||||||
compatible);
|
compatible);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
ret = fpga_load(devnum, (void *)fpga_image->load_addr,
|
ret = fpga_load(devnum, (void *)fpga_image->load_addr,
|
||||||
fpga_image->size, BIT_FULL, flags);
|
fpga_image->size, BIT_FULL, flags);
|
||||||
|
|
|
@ -179,3 +179,4 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0451
|
||||||
CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
|
CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
|
||||||
CONFIG_USB_GADGET_DOWNLOAD=y
|
CONFIG_USB_GADGET_DOWNLOAD=y
|
||||||
CONFIG_OF_LIBFDT_OVERLAY=y
|
CONFIG_OF_LIBFDT_OVERLAY=y
|
||||||
|
CONFIG_PHANDLE_CHECK_SEQ=y
|
||||||
|
|
|
@ -120,3 +120,4 @@ CONFIG_WDT=y
|
||||||
CONFIG_SHA384=y
|
CONFIG_SHA384=y
|
||||||
CONFIG_HEXDUMP=y
|
CONFIG_HEXDUMP=y
|
||||||
# CONFIG_EFI_LOADER is not set
|
# CONFIG_EFI_LOADER is not set
|
||||||
|
CONFIG_PHANDLE_CHECK_SEQ=y
|
||||||
|
|
|
@ -29,6 +29,7 @@ CONFIG_SILENT_CONSOLE=y
|
||||||
CONFIG_DISPLAY_BOARDINFO_LATE=y
|
CONFIG_DISPLAY_BOARDINFO_LATE=y
|
||||||
CONFIG_SPL_PAD_TO=0x7f8000
|
CONFIG_SPL_PAD_TO=0x7f8000
|
||||||
CONFIG_SPL_NO_BSS_LIMIT=y
|
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_SHARES_INIT_SP_ADDR is not set
|
||||||
CONFIG_SPL_STACK=0xff718000
|
CONFIG_SPL_STACK=0xff718000
|
||||||
CONFIG_SPL_STACK_R=y
|
CONFIG_SPL_STACK_R=y
|
||||||
|
|
|
@ -9,6 +9,7 @@ CONFIG_ENV_OFFSET=0x3F8000
|
||||||
CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64"
|
CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64"
|
||||||
CONFIG_ROCKCHIP_RK3399=y
|
CONFIG_ROCKCHIP_RK3399=y
|
||||||
CONFIG_TARGET_ROCKPRO64_RK3399=y
|
CONFIG_TARGET_ROCKPRO64_RK3399=y
|
||||||
|
CONFIG_BOOTSTAGE_STASH_ADDR=0xff8e0000
|
||||||
CONFIG_DEBUG_UART_BASE=0xFF1A0000
|
CONFIG_DEBUG_UART_BASE=0xFF1A0000
|
||||||
CONFIG_DEBUG_UART_CLOCK=24000000
|
CONFIG_DEBUG_UART_CLOCK=24000000
|
||||||
CONFIG_SPL_SPI_FLASH_SUPPORT=y
|
CONFIG_SPL_SPI_FLASH_SUPPORT=y
|
||||||
|
@ -17,6 +18,12 @@ CONFIG_SYS_LOAD_ADDR=0x800800
|
||||||
CONFIG_DEBUG_UART=y
|
CONFIG_DEBUG_UART=y
|
||||||
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
|
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
|
||||||
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x300000
|
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_USE_PREBOOT=y
|
||||||
CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-rockpro64.dtb"
|
CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-rockpro64.dtb"
|
||||||
CONFIG_DISPLAY_BOARDINFO_LATE=y
|
CONFIG_DISPLAY_BOARDINFO_LATE=y
|
||||||
|
@ -40,6 +47,7 @@ CONFIG_CMD_PCI=y
|
||||||
CONFIG_CMD_USB=y
|
CONFIG_CMD_USB=y
|
||||||
# CONFIG_CMD_SETEXPR is not set
|
# CONFIG_CMD_SETEXPR is not set
|
||||||
CONFIG_CMD_TIME=y
|
CONFIG_CMD_TIME=y
|
||||||
|
CONFIG_CMD_BOOTSTAGE=y
|
||||||
CONFIG_SPL_OF_CONTROL=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_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
|
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||||
|
|
|
@ -79,3 +79,4 @@ CONFIG_TIMER=y
|
||||||
CONFIG_MCHP_PIT64B_TIMER=y
|
CONFIG_MCHP_PIT64B_TIMER=y
|
||||||
CONFIG_OF_LIBFDT_OVERLAY=y
|
CONFIG_OF_LIBFDT_OVERLAY=y
|
||||||
# CONFIG_EFI_LOADER_HII is not set
|
# CONFIG_EFI_LOADER_HII is not set
|
||||||
|
CONFIG_PHANDLE_CHECK_SEQ=y
|
||||||
|
|
|
@ -79,3 +79,4 @@ CONFIG_TIMER=y
|
||||||
CONFIG_MCHP_PIT64B_TIMER=y
|
CONFIG_MCHP_PIT64B_TIMER=y
|
||||||
CONFIG_OF_LIBFDT_OVERLAY=y
|
CONFIG_OF_LIBFDT_OVERLAY=y
|
||||||
# CONFIG_EFI_LOADER_HII is not set
|
# CONFIG_EFI_LOADER_HII is not set
|
||||||
|
CONFIG_PHANDLE_CHECK_SEQ=y
|
||||||
|
|
|
@ -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
|
this timer include high resolution timers, PWMs or profile timers if
|
||||||
available. Most modern SOCs have a suitable timer for this. Make sure
|
available. Most modern SOCs have a suitable timer for this. Make sure
|
||||||
that you mark this timer (and anything it calls) with
|
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.
|
use it without causing an infinite loop.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -403,13 +403,6 @@ static int __maybe_unused pinctrl_post_bind(struct udevice *dev)
|
||||||
{
|
{
|
||||||
const struct pinctrl_ops *ops = pinctrl_get_ops(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) {
|
if (!ops) {
|
||||||
dev_dbg(dev, "ops is not set. Do not bind.\n");
|
dev_dbg(dev, "ops is not set. Do not bind.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -554,15 +554,6 @@ uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
|
||||||
*/
|
*/
|
||||||
int fdtdec_get_is_enabled(const void *blob, int node);
|
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.
|
* Checks that we have a valid fdt available to control U-Boot.
|
||||||
|
|
||||||
|
|
27
lib/Kconfig
27
lib/Kconfig
|
@ -316,7 +316,7 @@ config BITREVERSE
|
||||||
config TRACE
|
config TRACE
|
||||||
bool "Support for tracing of function calls and timing"
|
bool "Support for tracing of function calls and timing"
|
||||||
imply CMD_TRACE
|
imply CMD_TRACE
|
||||||
select TIMER_EARLY
|
imply TIMER_EARLY
|
||||||
help
|
help
|
||||||
Enables function tracing within U-Boot. This allows recording of call
|
Enables function tracing within U-Boot. This allows recording of call
|
||||||
traces including timing information. The command can write data to
|
traces including timing information. The command can write data to
|
||||||
|
@ -422,6 +422,7 @@ config TPM
|
||||||
config SPL_TPM
|
config SPL_TPM
|
||||||
bool "Trusted Platform Module (TPM) Support in SPL"
|
bool "Trusted Platform Module (TPM) Support in SPL"
|
||||||
depends on SPL_DM
|
depends on SPL_DM
|
||||||
|
imply SPL_CRC8
|
||||||
help
|
help
|
||||||
This enables support for TPMs which can be used to provide security
|
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
|
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
|
security applications, but it can be useful for providing a quick
|
||||||
checksum of a block of data.
|
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
|
config CRC32
|
||||||
def_bool y
|
def_bool y
|
||||||
help
|
help
|
||||||
|
@ -1042,6 +1060,13 @@ config LMB_RESERVED_REGIONS
|
||||||
Define the number of supported reserved regions in the library logical
|
Define the number of supported reserved regions in the library logical
|
||||||
memory blocks.
|
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
|
endmenu
|
||||||
|
|
||||||
menu "FWU Multi Bank Updates"
|
menu "FWU Multi Bank Updates"
|
||||||
|
|
|
@ -57,12 +57,13 @@ endif
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o
|
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o
|
||||||
ifeq ($(CONFIG_$(SPL_TPL_)TPM),y)
|
ifeq ($(CONFIG_$(SPL_TPL_)TPM),y)
|
||||||
obj-y += crc8.o
|
|
||||||
obj-$(CONFIG_TPM) += tpm_api.o
|
obj-$(CONFIG_TPM) += tpm_api.o
|
||||||
obj-$(CONFIG_TPM_V1) += tpm-v1.o
|
obj-$(CONFIG_TPM_V1) += tpm-v1.o
|
||||||
obj-$(CONFIG_TPM_V2) += tpm-v2.o
|
obj-$(CONFIG_TPM_V2) += tpm-v2.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o
|
||||||
|
|
||||||
obj-y += crypto/
|
obj-y += crypto/
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)GENERATE_ACPI_TABLE) += acpi/
|
obj-$(CONFIG_$(SPL_TPL_)GENERATE_ACPI_TABLE) += acpi/
|
||||||
|
|
|
@ -100,7 +100,7 @@ void *memset(void *s, int c, size_t n)
|
||||||
* func_ptr: Pointer to function being entered
|
* func_ptr: Pointer to function being entered
|
||||||
* caller: Pointer to function which called this function
|
* caller: Pointer to function which called this function
|
||||||
*/
|
*/
|
||||||
void __attribute__((no_instrument_function))
|
void notrace
|
||||||
__cyg_profile_func_enter(void *func_ptr, void *caller)
|
__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
|
* func_ptr: Pointer to function being entered
|
||||||
* caller: Pointer to function which called this function
|
* caller: Pointer to function which called this function
|
||||||
*/
|
*/
|
||||||
void __attribute__((no_instrument_function))
|
void notrace
|
||||||
__cyg_profile_func_exit(void *func_ptr, void *caller)
|
__cyg_profile_func_exit(void *func_ptr, void *caller)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
92
lib/fdtdec.c
92
lib/fdtdec.c
|
@ -13,6 +13,7 @@
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
|
#include <spl.h>
|
||||||
#include <env.h>
|
#include <env.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fdtdec.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
|
* Adding an extra check to distinguish DT nodes with
|
||||||
* same name
|
* same name
|
||||||
*/
|
*/
|
||||||
if (offset != fdt_path_offset(blob, prop))
|
if (IS_ENABLED(CONFIG_PHANDLE_CHECK_SEQ)) {
|
||||||
continue;
|
if (fdt_get_phandle(blob, offset) !=
|
||||||
|
fdt_get_phandle(blob, fdt_path_offset(blob, prop)))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
val = trailing_strtol(name);
|
val = trailing_strtol(name);
|
||||||
if (val != -1) {
|
if (val != -1) {
|
||||||
|
@ -586,6 +590,34 @@ int fdtdec_get_chosen_node(const void *blob, const char *name)
|
||||||
return fdt_path_offset(blob, prop);
|
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)
|
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
|
* FDT (prior to console ready) will need to make their own
|
||||||
* arrangements and do their own checks.
|
* arrangements and do their own checks.
|
||||||
*/
|
*/
|
||||||
assert(!fdtdec_prepare_fdt());
|
assert(!fdtdec_prepare_fdt(gd->fdt_blob));
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function is a little odd in that it accesses global data. At some
|
|
||||||
* point if the architecture board.c files merge this will make more sense.
|
|
||||||
* Even now, it is common code.
|
|
||||||
*/
|
|
||||||
int fdtdec_prepare_fdt(void)
|
|
||||||
{
|
|
||||||
if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
|
|
||||||
fdt_check_header(gd->fdt_blob)) {
|
|
||||||
#ifdef CONFIG_SPL_BUILD
|
|
||||||
puts("Missing DTB\n");
|
|
||||||
#else
|
|
||||||
printf("No valid device tree binary found at %p\n",
|
|
||||||
gd->fdt_blob);
|
|
||||||
# ifdef DEBUG
|
|
||||||
if (gd->fdt_blob) {
|
|
||||||
printf("fdt_blob=%p\n", gd->fdt_blob);
|
|
||||||
print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
|
|
||||||
32, 0);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1229,6 +1234,29 @@ static void *fdt_find_separate(void)
|
||||||
#else
|
#else
|
||||||
/* FDT is at end of image */
|
/* FDT is at end of image */
|
||||||
fdt_blob = (ulong *)&_end;
|
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
|
#endif
|
||||||
|
|
||||||
return fdt_blob;
|
return fdt_blob;
|
||||||
|
@ -1666,7 +1694,7 @@ int fdtdec_setup(void)
|
||||||
if (CONFIG_IS_ENABLED(MULTI_DTB_FIT))
|
if (CONFIG_IS_ENABLED(MULTI_DTB_FIT))
|
||||||
setup_multi_dtb_fit();
|
setup_multi_dtb_fit();
|
||||||
|
|
||||||
ret = fdtdec_prepare_fdt();
|
ret = fdtdec_prepare_fdt(gd->fdt_blob);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = fdtdec_board_setup(gd->fdt_blob);
|
ret = fdtdec_board_setup(gd->fdt_blob);
|
||||||
oftree_reset();
|
oftree_reset();
|
||||||
|
@ -1698,7 +1726,7 @@ int fdtdec_resetup(int *rescan)
|
||||||
|
|
||||||
*rescan = 1;
|
*rescan = 1;
|
||||||
gd->fdt_blob = fdt_blob;
|
gd->fdt_blob = fdt_blob;
|
||||||
return fdtdec_prepare_fdt();
|
return fdtdec_prepare_fdt(fdt_blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
29
lib/trace.c
29
lib/trace.c
|
@ -40,7 +40,8 @@ struct trace_hdr {
|
||||||
int max_depth;
|
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))
|
static inline uintptr_t __attribute__((no_instrument_function))
|
||||||
func_ptr_to_num(void *func_ptr)
|
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
|
* 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;
|
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
|
* 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.
|
* 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;
|
volatile gd_t *temp_gd = trace_gd;
|
||||||
|
|
||||||
|
@ -91,18 +92,17 @@ static void __attribute__((no_instrument_function)) trace_swap_gd(void)
|
||||||
|
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
|
static void notrace add_ftrace(void *func_ptr, void *caller, ulong flags)
|
||||||
void *caller, ulong flags)
|
|
||||||
{
|
{
|
||||||
if (hdr->depth > hdr->depth_limit) {
|
if (hdr->depth > hdr->depth_limit) {
|
||||||
hdr->ftrace_too_deep_count++;
|
hdr->ftrace_too_deep_count++;
|
||||||
|
@ -118,7 +118,7 @@ static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
|
||||||
hdr->ftrace_count++;
|
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) {
|
if (hdr->ftrace_count < hdr->ftrace_size) {
|
||||||
struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count];
|
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
|
* @func_ptr: pointer to function being entered
|
||||||
* @caller: pointer to function which called this function
|
* @caller: pointer to function which called this function
|
||||||
*/
|
*/
|
||||||
void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
|
void notrace __cyg_profile_func_enter(void *func_ptr, void *caller)
|
||||||
void *func_ptr, void *caller)
|
|
||||||
{
|
{
|
||||||
if (trace_enabled) {
|
if (trace_enabled) {
|
||||||
int func;
|
int func;
|
||||||
|
@ -167,8 +166,7 @@ void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
|
||||||
* @func_ptr: pointer to function being entered
|
* @func_ptr: pointer to function being entered
|
||||||
* @caller: pointer to function which called this function
|
* @caller: pointer to function which called this function
|
||||||
*/
|
*/
|
||||||
void __attribute__((no_instrument_function)) __cyg_profile_func_exit(
|
void notrace __cyg_profile_func_exit(void *func_ptr, void *caller)
|
||||||
void *func_ptr, void *caller)
|
|
||||||
{
|
{
|
||||||
if (trace_enabled) {
|
if (trace_enabled) {
|
||||||
trace_swap_gd();
|
trace_swap_gd();
|
||||||
|
@ -327,7 +325,7 @@ void trace_print_stats(void)
|
||||||
puts(" calls not traced due to depth\n");
|
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;
|
trace_enabled = enabled != 0;
|
||||||
}
|
}
|
||||||
|
@ -339,8 +337,7 @@ void __attribute__((no_instrument_function)) trace_set_enabled(int enabled)
|
||||||
* @buff_size: Size of trace buffer
|
* @buff_size: Size of trace buffer
|
||||||
* Return: 0 if ok
|
* Return: 0 if ok
|
||||||
*/
|
*/
|
||||||
int __attribute__((no_instrument_function)) trace_init(void *buff,
|
int notrace trace_init(void *buff, size_t buff_size)
|
||||||
size_t buff_size)
|
|
||||||
{
|
{
|
||||||
ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
|
ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
|
||||||
size_t needed;
|
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
|
* 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;
|
ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
|
||||||
size_t buff_size = CONFIG_TRACE_EARLY_SIZE;
|
size_t buff_size = CONFIG_TRACE_EARLY_SIZE;
|
||||||
|
|
|
@ -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
|
since it is assumed that images are XIP and the offsets already include the
|
||||||
address.
|
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)
|
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` property disables this just for a single entry. Put the
|
||||||
`no-expanded` boolean property in the node to select this behaviour.
|
`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
|
The attributes supported for images and sections are described below. Several
|
||||||
are similar to those for entries.
|
are similar to those for entries.
|
||||||
|
|
||||||
|
@ -782,6 +799,37 @@ align-default:
|
||||||
symlink:
|
symlink:
|
||||||
Adds a symlink to the image with string given in the symlink property.
|
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
|
Examples of the above options can be found in the tests. See the
|
||||||
tools/binman/test directory.
|
tools/binman/test directory.
|
||||||
|
|
||||||
|
@ -836,6 +884,11 @@ name-prefix:
|
||||||
renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
|
renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
|
||||||
distinguish binaries with otherwise identical names.
|
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
|
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.
|
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
|
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
|
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
|
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
|
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
|
position 'image-pos', as opposed to 'offset' which is relative to the containing
|
||||||
|
|
|
@ -552,6 +552,7 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
|
||||||
image.SetAllowMissing(allow_missing)
|
image.SetAllowMissing(allow_missing)
|
||||||
image.SetAllowFakeBlob(allow_fake_blobs)
|
image.SetAllowFakeBlob(allow_fake_blobs)
|
||||||
image.GetEntryContents()
|
image.GetEntryContents()
|
||||||
|
image.drop_absent()
|
||||||
image.GetEntryOffsets()
|
image.GetEntryOffsets()
|
||||||
|
|
||||||
# We need to pack the entries to figure out where everything
|
# 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()
|
image.BuildImage()
|
||||||
if write_map:
|
if write_map:
|
||||||
image.WriteMap()
|
image.WriteMap()
|
||||||
|
|
||||||
missing_list = []
|
missing_list = []
|
||||||
image.CheckMissing(missing_list)
|
image.CheckMissing(missing_list)
|
||||||
if missing_list:
|
if missing_list:
|
||||||
tout.warning("Image '%s' is missing external blobs and is non-functional: %s" %
|
tout.warning("Image '%s' is missing external blobs and is non-functional: %s" %
|
||||||
(image.name, ' '.join([e.name for e in missing_list])))
|
(image.name, ' '.join([e.name for e in missing_list])))
|
||||||
_ShowHelpForMissingBlobs(missing_list)
|
_ShowHelpForMissingBlobs(missing_list)
|
||||||
|
|
||||||
faked_list = []
|
faked_list = []
|
||||||
image.CheckFakedBlobs(faked_list)
|
image.CheckFakedBlobs(faked_list)
|
||||||
if 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 '%s' has faked external blobs and is non-functional: %s" %
|
||||||
(image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
|
(image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
|
||||||
for e in faked_list])))
|
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 = []
|
missing_bintool_list = []
|
||||||
image.check_missing_bintools(missing_bintool_list)
|
image.check_missing_bintools(missing_bintool_list)
|
||||||
if missing_bintool_list:
|
if missing_bintool_list:
|
||||||
|
|
|
@ -210,7 +210,31 @@ def GetPackString(sym, msg):
|
||||||
raise ValueError('%s has size %d: only 4 and 8 are supported' %
|
raise ValueError('%s has size %d: only 4 and 8 are supported' %
|
||||||
(msg, sym.size))
|
(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
|
"""Replace all symbols in an entry with their correct values
|
||||||
|
|
||||||
The entry contents is updated so that values for referenced symbols will be
|
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: Entry to process
|
entry: Entry to process
|
||||||
section: Section which can be used to lookup symbol values
|
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)
|
fname = tools.get_input_filename(elf_fname)
|
||||||
syms = GetSymbols(fname, ['image', 'binman'])
|
syms = GetSymbols(fname, ['image', 'binman'])
|
||||||
if is_elf:
|
if is_elf:
|
||||||
|
@ -243,7 +270,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
|
||||||
if not syms:
|
if not syms:
|
||||||
tout.debug('LookupAndWriteSymbols: no syms')
|
tout.debug('LookupAndWriteSymbols: no syms')
|
||||||
return
|
return
|
||||||
base = syms.get('__image_copy_start')
|
base = syms.get(base_sym)
|
||||||
if not base and not is_elf:
|
if not base and not is_elf:
|
||||||
tout.debug('LookupAndWriteSymbols: no base')
|
tout.debug('LookupAndWriteSymbols: no base')
|
||||||
return
|
return
|
||||||
|
@ -518,3 +545,18 @@ def read_loadable_segments(data):
|
||||||
rend = start + segment['p_filesz']
|
rend = start + segment['p_filesz']
|
||||||
segments.append((i, segment['p_paddr'], data[start:rend]))
|
segments.append((i, segment['p_paddr'], data[start:rend]))
|
||||||
return segments, entry
|
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
|
||||||
|
|
|
@ -348,6 +348,16 @@ class TestElf(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
elf.ELF_TOOLS = old_val
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -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
|
obtained from the list of available device-tree files, managed by the
|
||||||
'state' module.
|
'state' module.
|
||||||
|
|
||||||
Additional Properties / Entry arguments:
|
Additional attributes:
|
||||||
- prepend: Header type to use:
|
prepend: Header used (e.g. 'length')
|
||||||
length: 32-bit length header
|
|
||||||
|
|
||||||
|
|
||||||
.. _etype_blob_ext:
|
.. _etype_blob_ext:
|
||||||
|
@ -1178,11 +1178,13 @@ Properties / Entry arguments:
|
||||||
- multiple-data-files: boolean to tell binman to pass all files as
|
- multiple-data-files: boolean to tell binman to pass all files as
|
||||||
datafiles to mkimage instead of creating a temporary file the result
|
datafiles to mkimage instead of creating a temporary file the result
|
||||||
of datafiles concatenation
|
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
|
The data passed to mkimage via the -d flag is collected from subnodes of the
|
||||||
mkimage node, e.g.::
|
mkimage node, e.g.::
|
||||||
|
|
||||||
mkimage {
|
mkimage {
|
||||||
|
filename = "imximage.bin";
|
||||||
args = "-n test -T imximage";
|
args = "-n test -T imximage";
|
||||||
|
|
||||||
u-boot-spl {
|
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
|
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>
|
mkimage -d <data_file> -n test -T imximage <output_file>
|
||||||
|
|
||||||
The output from mkimage then becomes part of the image produced by
|
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
|
binman but also is written into `imximage.bin` file. If you need to put
|
||||||
a section, or just multiple subnodes like this::
|
multiple things in the data file, you can use a section, or just multiple
|
||||||
|
subnodes like this::
|
||||||
|
|
||||||
mkimage {
|
mkimage {
|
||||||
args = "-n test -T imximage";
|
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::
|
To pass all datafiles untouched to mkimage::
|
||||||
|
|
||||||
mkimage {
|
mkimage {
|
||||||
args = "-n rk3399 -T rkspi";
|
args = "-n rk3399 -T rkspi";
|
||||||
multiple-data-files;
|
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
|
This calls mkimage to create a Rockchip RK3399-specific first stage
|
||||||
|
@ -1242,17 +1248,17 @@ the 'data-to-imagename' property::
|
||||||
|
|
||||||
mkimage {
|
mkimage {
|
||||||
args = "-T imximage";
|
args = "-T imximage";
|
||||||
data-to-imagename';
|
data-to-imagename;
|
||||||
|
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
That will pass the data to mkimage both as the data file (with -d) and as
|
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 {
|
mkimage {
|
||||||
args = "-T imximage";
|
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.
|
-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:
|
.. _etype_opensbi:
|
||||||
|
|
||||||
Entry: opensbi: RISC-V OpenSBI fw_dynamic blob
|
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
|
be written at offset 4 in the image file, since the first 16 bytes are
|
||||||
skipped when writing.
|
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
|
Since a section is also an entry, it inherits all the properies of entries
|
||||||
too.
|
too.
|
||||||
|
|
||||||
|
@ -1497,12 +1521,47 @@ Entry: tee-os: Entry containing an OP-TEE Trusted OS (TEE) blob
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
- tee-os-path: Filename of file to read into entry. This is typically
|
- 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.
|
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
|
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.
|
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:
|
.. _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
|
to relocate itself at runtime. The binary typically includes a device tree
|
||||||
blob at the end of it.
|
blob at the end of it.
|
||||||
|
|
||||||
U-Boot can access binman symbols at runtime. See:
|
U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (fdt)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
|
||||||
|
|
||||||
Note that this entry is automatically replaced with u-boot-expanded unless
|
Note that this entry is automatically replaced with u-boot-expanded unless
|
||||||
--no-expanded is used or the node has a 'no-expanded' property.
|
--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.
|
to run from the correct address if direct flash execution is possible (e.g.
|
||||||
on x86 devices).
|
on x86 devices).
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
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
|
expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
|
||||||
u-boot-spl-dtb
|
u-boot-spl-dtb
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
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
|
address in SRAM, or written to run from the correct address if direct
|
||||||
flash execution is possible (e.g. on x86 devices).
|
flash execution is possible (e.g. on x86 devices).
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
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
|
expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
|
||||||
u-boot-tpl-dtb
|
u-boot-tpl-dtb
|
||||||
|
|
||||||
TPL can access binman symbols at runtime. See:
|
TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
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:
|
.. _etype_u_boot_with_ucode_ptr:
|
||||||
|
|
||||||
Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer
|
Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer
|
||||||
|
|
|
@ -73,7 +73,9 @@ class Entry(object):
|
||||||
compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
|
compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
|
||||||
orig_offset: Original offset value read from node
|
orig_offset: Original offset value read from node
|
||||||
orig_size: Original size 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
|
allow_missing: Allow children of this entry to be missing (used by
|
||||||
subclasses such as Entry_section)
|
subclasses such as Entry_section)
|
||||||
allow_fake: Allow creating a dummy fake file if the blob file is not
|
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
|
file, or is a binary file produced from an ELF file
|
||||||
auto_write_symbols (bool): True to write ELF symbols into this entry's
|
auto_write_symbols (bool): True to write ELF symbols into this entry's
|
||||||
contents
|
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
|
fake_dir = None
|
||||||
|
|
||||||
|
@ -133,6 +141,11 @@ class Entry(object):
|
||||||
self.comp_bintool = None
|
self.comp_bintool = None
|
||||||
self.elf_fname = None
|
self.elf_fname = None
|
||||||
self.auto_write_symbols = auto_write_symbols
|
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
|
@staticmethod
|
||||||
def FindEntryClass(etype, expanded):
|
def FindEntryClass(etype, expanded):
|
||||||
|
@ -284,9 +297,15 @@ class Entry(object):
|
||||||
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
|
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
|
||||||
self.extend_size = fdt_util.GetBool(self._node, 'extend-size')
|
self.extend_size = fdt_util.GetBool(self._node, 'extend-size')
|
||||||
self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
|
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
|
# This is only supported by blobs and sections at present
|
||||||
self.compress = fdt_util.GetString(self._node, 'compress', 'none')
|
self.compress = fdt_util.GetString(self._node, 'compress', 'none')
|
||||||
|
self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node,
|
||||||
|
'offset-from-elf')
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return None
|
return None
|
||||||
|
@ -444,7 +463,7 @@ class Entry(object):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if the contents were found, False if another call is needed
|
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
|
# No contents by default: subclasses can implement this
|
||||||
return True
|
return True
|
||||||
|
@ -483,7 +502,10 @@ class Entry(object):
|
||||||
if self.offset_unset:
|
if self.offset_unset:
|
||||||
self.Raise('No offset set with offset-unset: should another '
|
self.Raise('No offset set with offset-unset: should another '
|
||||||
'entry provide this correct offset?')
|
'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 = self.pad_before + self.contents_size + self.pad_after
|
||||||
needed = tools.align(needed, self.align_size)
|
needed = tools.align(needed, self.align_size)
|
||||||
size = self.size
|
size = self.size
|
||||||
|
@ -572,7 +594,9 @@ class Entry(object):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bytes content of the entry, excluding any padding. If the entry is
|
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))
|
self.Detail('GetData: size %s' % to_hex_size(self.data))
|
||||||
return self.data
|
return self.data
|
||||||
|
@ -659,7 +683,7 @@ class Entry(object):
|
||||||
# Check if we are writing symbols into an ELF file
|
# Check if we are writing symbols into an ELF file
|
||||||
is_elf = self.GetDefaultFilename() == self.elf_fname
|
is_elf = self.GetDefaultFilename() == self.elf_fname
|
||||||
elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(),
|
elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(),
|
||||||
is_elf)
|
is_elf, self.elf_base_sym)
|
||||||
|
|
||||||
def CheckEntries(self):
|
def CheckEntries(self):
|
||||||
"""Check that the entry offsets are correct
|
"""Check that the entry offsets are correct
|
||||||
|
@ -1034,14 +1058,15 @@ features to produce new behaviours.
|
||||||
self.allow_fake = allow_fake
|
self.allow_fake = allow_fake
|
||||||
|
|
||||||
def CheckMissing(self, missing_list):
|
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:
|
Args:
|
||||||
missing_list: List of Entry objects to be added to
|
missing_list: List of Entry objects to be added to
|
||||||
"""
|
"""
|
||||||
if self.missing:
|
if self.missing and not self.optional:
|
||||||
missing_list.append(self)
|
missing_list.append(self)
|
||||||
|
|
||||||
def check_fake_fname(self, fname, size=0):
|
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
|
# This is meaningless for anything other than blobs
|
||||||
pass
|
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):
|
def GetAllowMissing(self):
|
||||||
"""Get whether a section allows missing external blobs
|
"""Get whether a section allows missing external blobs
|
||||||
|
|
||||||
|
@ -1281,3 +1317,31 @@ features to produce new behaviours.
|
||||||
not_present.append(prop)
|
not_present.append(prop)
|
||||||
if not_present:
|
if not_present:
|
||||||
self.Raise(f"'{self.etype}' entry is missing properties: {' '.join(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
|
||||||
|
|
|
@ -63,6 +63,7 @@ class Entry__testing(Entry):
|
||||||
'bad-update-contents-twice')
|
'bad-update-contents-twice')
|
||||||
self.return_contents_later = fdt_util.GetBool(self._node,
|
self.return_contents_later = fdt_util.GetBool(self._node,
|
||||||
'return-contents-later')
|
'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.
|
# Set to True when the entry is ready to process the FDT.
|
||||||
self.process_fdt_ready = False
|
self.process_fdt_ready = False
|
||||||
|
@ -119,6 +120,8 @@ class Entry__testing(Entry):
|
||||||
if self.require_bintool_for_contents:
|
if self.require_bintool_for_contents:
|
||||||
if self.bintool_for_contents is None:
|
if self.bintool_for_contents is None:
|
||||||
self.Raise("Required bintool unusable in ObtainContents()")
|
self.Raise("Required bintool unusable in ObtainContents()")
|
||||||
|
if self.set_to_absent:
|
||||||
|
self.mark_absent('for testing purposes')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def GetOffsets(self):
|
def GetOffsets(self):
|
||||||
|
|
|
@ -35,11 +35,17 @@ class Entry_blob(Entry):
|
||||||
super().__init__(section, etype, node,
|
super().__init__(section, etype, node,
|
||||||
auto_write_symbols=auto_write_symbols)
|
auto_write_symbols=auto_write_symbols)
|
||||||
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
|
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):
|
def ObtainContents(self, fake_size=0):
|
||||||
self._filename = self.GetDefaultFilename()
|
self._filename = self.GetDefaultFilename()
|
||||||
self._pathname = tools.get_input_filename(self._filename,
|
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
|
# Allow the file to be missing
|
||||||
if not self._pathname:
|
if not self._pathname:
|
||||||
self._pathname, faked = self.check_fake_fname(self._filename,
|
self._pathname, faked = self.check_fake_fname(self._filename,
|
||||||
|
|
|
@ -392,8 +392,8 @@ class Entry_fit(Entry_section):
|
||||||
|
|
||||||
_add_entries(self._node, 0, self._node)
|
_add_entries(self._node, 0, self._node)
|
||||||
|
|
||||||
# Keep a copy of all entries, including generator entries, since these
|
# Keep a copy of all entries, including generator entries, since those
|
||||||
# removed from self._entries later.
|
# are removed from self._entries later.
|
||||||
self._priv_entries = dict(self._entries)
|
self._priv_entries = dict(self._entries)
|
||||||
|
|
||||||
def BuildSectionData(self, required):
|
def BuildSectionData(self, required):
|
||||||
|
@ -540,50 +540,50 @@ class Entry_fit(Entry_section):
|
||||||
else:
|
else:
|
||||||
self.Raise("Generator node requires 'fit,fdt-list' property")
|
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
|
"""Add nodes for the ELF file, one per group of contiguous segments
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
base_node (Node): Template node from the binman definition
|
base_node (Node): Template node from the binman definition
|
||||||
node (Node): Node to replace (in the FIT being built)
|
node (Node): Node to replace (in the FIT being built)
|
||||||
data (bytes): ELF-format data to process (may be empty)
|
segments (list): list of segments, each:
|
||||||
missing (bool): True if any of the data is missing
|
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
|
for (seq, start, data) in segments:
|
||||||
# show an error
|
node_name = node.name[1:].replace('SEQ', str(seq + 1))
|
||||||
if not missing:
|
with fsw.add_node(node_name):
|
||||||
try:
|
loadables.append(node_name)
|
||||||
segments, entry = elf.read_loadable_segments(elf_data)
|
for pname, prop in node.props.items():
|
||||||
except ValueError as exc:
|
if not pname.startswith('fit,'):
|
||||||
self._raise_subnode(node,
|
fsw.property(pname, prop.bytes)
|
||||||
f'Failed to read ELF file: {str(exc)}')
|
elif pname == 'fit,load':
|
||||||
for (seq, start, data) in segments:
|
fsw.property_u32('load', start)
|
||||||
node_name = node.name[1:].replace('SEQ', str(seq + 1))
|
elif pname == 'fit,entry':
|
||||||
with fsw.add_node(node_name):
|
if seq == 0:
|
||||||
loadables.append(node_name)
|
fsw.property_u32('entry', entry_addr)
|
||||||
for pname, prop in node.props.items():
|
elif pname == 'fit,data':
|
||||||
if not pname.startswith('fit,'):
|
fsw.property('data', bytes(data))
|
||||||
fsw.property(pname, prop.bytes)
|
elif pname != 'fit,operation':
|
||||||
elif pname == 'fit,load':
|
self._raise_subnode(
|
||||||
fsw.property_u32('load', start)
|
node, f"Unknown directive '{pname}'")
|
||||||
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}'")
|
|
||||||
|
|
||||||
def _gen_node(base_node, node, depth, in_images, entry):
|
def _gen_node(base_node, node, depth, in_images, entry):
|
||||||
"""Generate nodes from a template
|
"""Generate nodes from a template
|
||||||
|
|
||||||
This creates one node for each member of self._fdts using the
|
This creates one or more nodes depending on the fit,operation being
|
||||||
provided template. If a property value contains 'NAME' it is
|
used.
|
||||||
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
|
For OP_GEN_FDT_NODES it creates one node for each member of
|
||||||
first.
|
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:
|
Args:
|
||||||
base_node (Node): Base Node of the FIT (with 'description'
|
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)
|
depth (int): Current node depth (0 is the base 'fit' node)
|
||||||
in_images (bool): True if this is inside the 'images' node, so
|
in_images (bool): True if this is inside the 'images' node, so
|
||||||
that 'data' properties should be generated
|
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)
|
oper = self._get_operation(base_node, node)
|
||||||
if oper == OP_GEN_FDT_NODES:
|
if oper == OP_GEN_FDT_NODES:
|
||||||
|
@ -600,13 +602,28 @@ class Entry_fit(Entry_section):
|
||||||
# Entry_section.ObtainContents() either returns True or
|
# Entry_section.ObtainContents() either returns True or
|
||||||
# raises an exception.
|
# raises an exception.
|
||||||
data = None
|
data = None
|
||||||
missing_list = []
|
missing_opt_list = []
|
||||||
entry.ObtainContents()
|
entry.ObtainContents()
|
||||||
entry.Pack(0)
|
entry.Pack(0)
|
||||||
data = entry.GetData()
|
entry.CheckMissing(missing_opt_list)
|
||||||
entry.CheckMissing(missing_list)
|
entry.CheckOptional(missing_opt_list)
|
||||||
|
|
||||||
_gen_split_elf(base_node, node, data, bool(missing_list))
|
# If any pieces are missing, skip this. The missing entries will
|
||||||
|
# show an error
|
||||||
|
if not missing_opt_list:
|
||||||
|
segs = entry.read_elf_segments()
|
||||||
|
if segs:
|
||||||
|
segments, entry_addr = segs
|
||||||
|
else:
|
||||||
|
elf_data = entry.GetData()
|
||||||
|
try:
|
||||||
|
segments, entry_addr = (
|
||||||
|
elf.read_loadable_segments(elf_data))
|
||||||
|
except ValueError as exc:
|
||||||
|
self._raise_subnode(
|
||||||
|
node, f'Failed to read ELF file: {str(exc)}')
|
||||||
|
|
||||||
|
_gen_split_elf(base_node, node, segments, entry_addr)
|
||||||
|
|
||||||
def _add_node(base_node, depth, node):
|
def _add_node(base_node, depth, node):
|
||||||
"""Add nodes to the output FIT
|
"""Add nodes to the output FIT
|
||||||
|
@ -638,8 +655,7 @@ class Entry_fit(Entry_section):
|
||||||
|
|
||||||
for subnode in node.subnodes:
|
for subnode in node.subnodes:
|
||||||
subnode_path = f'{rel_path}/{subnode.name}'
|
subnode_path = f'{rel_path}/{subnode.name}'
|
||||||
if has_images and not (subnode.name.startswith('hash') or
|
if has_images and not self.IsSpecialSubnode(subnode):
|
||||||
subnode.name.startswith('signature')):
|
|
||||||
# This subnode is a content node not meant to appear in
|
# This subnode is a content node not meant to appear in
|
||||||
# the FIT (e.g. "/images/kernel/u-boot"), so don't call
|
# the FIT (e.g. "/images/kernel/u-boot"), so don't call
|
||||||
# fsw.add_node() or _add_node() for it.
|
# fsw.add_node() or _add_node() for it.
|
||||||
|
|
|
@ -57,24 +57,24 @@ class Entry_mkimage(Entry):
|
||||||
Note that binman places the contents (here SPL and TPL) into a single file
|
Note that binman places the contents (here SPL and TPL) into a single file
|
||||||
and passes that to mkimage using the -d option.
|
and passes that to mkimage using the -d option.
|
||||||
|
|
||||||
To pass all datafiles untouched to mkimage::
|
To pass all datafiles untouched to mkimage::
|
||||||
|
|
||||||
mkimage {
|
mkimage {
|
||||||
args = "-n rk3399 -T rkspi";
|
args = "-n rk3399 -T rkspi";
|
||||||
multiple-data-files;
|
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
|
This calls mkimage to create a Rockchip RK3399-specific first stage
|
||||||
bootloader, made of TPL+SPL. Since this first stage bootloader requires to
|
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
|
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
|
directly, binman is told to not perform the concatenation of datafiles prior
|
||||||
to passing the data to mkimage.
|
to passing the data to mkimage.
|
||||||
|
|
||||||
To use CONFIG options in the arguments, use a string list instead, as in
|
To use CONFIG options in the arguments, use a string list instead, as in
|
||||||
this example which also produces four arguments::
|
this example which also produces four arguments::
|
||||||
|
|
25
tools/binman/etype/null.py
Normal file
25
tools/binman/etype/null.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright 2023 Google LLC
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
from binman.entry import Entry
|
||||||
|
from dtoc import fdt_util
|
||||||
|
from patman import tools
|
||||||
|
|
||||||
|
class Entry_null(Entry):
|
||||||
|
"""An entry which has no contents of its own
|
||||||
|
|
||||||
|
Note that the size property must be set since otherwise this entry does not
|
||||||
|
know how large it should be.
|
||||||
|
|
||||||
|
The contents are set by the containing section, e.g. the section's pad
|
||||||
|
byte.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
super().__init__(section, etype, node)
|
||||||
|
self.required_props = ['size']
|
||||||
|
|
||||||
|
def ObtainContents(self):
|
||||||
|
# null contents
|
||||||
|
return None
|
|
@ -144,6 +144,10 @@ class Entry_section(Entry):
|
||||||
be written at offset 4 in the image file, since the first 16 bytes are
|
be written at offset 4 in the image file, since the first 16 bytes are
|
||||||
skipped when writing.
|
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
|
Since a section is also an entry, it inherits all the properies of entries
|
||||||
too.
|
too.
|
||||||
|
|
||||||
|
@ -163,6 +167,18 @@ class Entry_section(Entry):
|
||||||
self._skip_at_start = None
|
self._skip_at_start = None
|
||||||
self._end_4gb = False
|
self._end_4gb = False
|
||||||
self._ignore_missing = 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):
|
def ReadNode(self):
|
||||||
"""Read properties from the section node"""
|
"""Read properties from the section node"""
|
||||||
|
@ -183,12 +199,14 @@ class Entry_section(Entry):
|
||||||
self._skip_at_start = 0
|
self._skip_at_start = 0
|
||||||
self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
|
self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
|
||||||
self.align_default = fdt_util.GetInt(self._node, 'align-default', 0)
|
self.align_default = fdt_util.GetInt(self._node, 'align-default', 0)
|
||||||
|
self._filename = fdt_util.GetString(self._node, 'filename',
|
||||||
|
self._filename)
|
||||||
|
|
||||||
self.ReadEntries()
|
self.ReadEntries()
|
||||||
|
|
||||||
def ReadEntries(self):
|
def ReadEntries(self):
|
||||||
for node in self._node.subnodes:
|
for node in self._node.subnodes:
|
||||||
if node.name.startswith('hash') or node.name.startswith('signature'):
|
if self.IsSpecialSubnode(node):
|
||||||
continue
|
continue
|
||||||
entry = Entry.Create(self, node,
|
entry = Entry.Create(self, node,
|
||||||
expanded=self.GetImage().use_expanded,
|
expanded=self.GetImage().use_expanded,
|
||||||
|
@ -258,6 +276,7 @@ class Entry_section(Entry):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
entry: Entry to check
|
entry: Entry to check
|
||||||
|
entry_data: Data for the entry, False if is null
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Contents of the entry along with any pad bytes before and
|
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().
|
# earlier in the image description. See testCollectionSection().
|
||||||
if not required and entry_data is None:
|
if not required and entry_data is None:
|
||||||
return 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
|
# Handle empty space before the entry
|
||||||
pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
|
pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
|
||||||
if pad > 0:
|
if pad > 0:
|
||||||
section_data += tools.get_bytes(self._pad_byte, pad)
|
section_data += tools.get_bytes(self._pad_byte, pad)
|
||||||
|
|
||||||
# Add in the actual entry data
|
# 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' %
|
self.Detail('GetData: %d entries, total size %#x' %
|
||||||
(len(self._entries), len(section_data)))
|
(len(self._entries), len(section_data)))
|
||||||
|
@ -348,7 +385,8 @@ class Entry_section(Entry):
|
||||||
"""Get the contents of an entry
|
"""Get the contents of an entry
|
||||||
|
|
||||||
This builds the contents of the section, stores this as the contents of
|
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:
|
Args:
|
||||||
required: True if the data must be present, False if it is OK to
|
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:
|
if data is None:
|
||||||
return None
|
return None
|
||||||
self.SetContents(data)
|
self.SetContents(data)
|
||||||
|
if self._filename:
|
||||||
|
tools.write_file(tools.get_output_filename(self._filename), data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def GetOffsets(self):
|
def GetOffsets(self):
|
||||||
|
@ -439,12 +479,13 @@ class Entry_section(Entry):
|
||||||
(entry.offset, entry.offset, entry.size, entry.size,
|
(entry.offset, entry.offset, entry.size, entry.size,
|
||||||
self._node.path, self._skip_at_start,
|
self._node.path, self._skip_at_start,
|
||||||
self._skip_at_start, max_size, max_size))
|
self._skip_at_start, max_size, max_size))
|
||||||
if entry.offset < offset and entry.size:
|
if not entry.overlap:
|
||||||
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
|
if entry.offset < offset and entry.size:
|
||||||
"ending at %#x (%d)" %
|
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' ending at %#x (%d)" %
|
||||||
(entry.offset, entry.offset, prev_name, offset, offset))
|
(entry.offset, entry.offset, prev_name, offset,
|
||||||
offset = entry.offset + entry.size
|
offset))
|
||||||
prev_name = entry.GetPath()
|
offset = entry.offset + entry.size
|
||||||
|
prev_name = entry.GetPath()
|
||||||
|
|
||||||
def WriteSymbols(self, section):
|
def WriteSymbols(self, section):
|
||||||
"""Write symbol values into binary files for access at run time"""
|
"""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):
|
def GetEntryContents(self, skip_entry=None):
|
||||||
"""Call ObtainContents() for each entry in the section
|
"""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):
|
def _CheckDone(entry):
|
||||||
if entry != skip_entry:
|
if entry != skip_entry:
|
||||||
if not entry.ObtainContents():
|
if entry.ObtainContents() is False:
|
||||||
next_todo.append(entry)
|
next_todo.append(entry)
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
|
@ -706,6 +750,10 @@ class Entry_section(Entry):
|
||||||
todo)
|
todo)
|
||||||
return True
|
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):
|
def _SetEntryOffsetSize(self, name, offset, size):
|
||||||
"""Set the offset and size of an entry
|
"""Set the offset and size of an entry
|
||||||
|
|
||||||
|
@ -846,7 +894,8 @@ class Entry_section(Entry):
|
||||||
def CheckMissing(self, missing_list):
|
def CheckMissing(self, missing_list):
|
||||||
"""Check if any entries in this section have missing external blobs
|
"""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:
|
Args:
|
||||||
missing_list: List of Entry objects to be added to
|
missing_list: List of Entry objects to be added to
|
||||||
|
@ -865,6 +914,17 @@ class Entry_section(Entry):
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.CheckFakedBlobs(faked_blobs_list)
|
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):
|
def check_missing_bintools(self, missing_list):
|
||||||
"""Check if any entries in this section have missing bintools
|
"""Check if any entries in this section have missing bintools
|
||||||
|
|
||||||
|
@ -931,3 +991,12 @@ class Entry_section(Entry):
|
||||||
super().AddBintools(btools)
|
super().AddBintools(btools)
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.AddBintools(btools)
|
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
|
||||||
|
|
|
@ -4,19 +4,93 @@
|
||||||
# Entry-type module for OP-TEE Trusted OS firmware blob
|
# 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.etype.blob_named_by_arg import Entry_blob_named_by_arg
|
||||||
|
from binman import elf
|
||||||
|
|
||||||
class Entry_tee_os(Entry_blob_named_by_arg):
|
class Entry_tee_os(Entry_blob_named_by_arg):
|
||||||
"""Entry containing an OP-TEE Trusted OS (TEE) blob
|
"""Entry containing an OP-TEE Trusted OS (TEE) blob
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
- tee-os-path: Filename of file to read into entry. This is typically
|
- 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.
|
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
|
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.
|
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):
|
def __init__(self, section, etype, node):
|
||||||
super().__init__(section, etype, node, 'tee-os')
|
super().__init__(section, etype, node, 'tee-os')
|
||||||
self.external = True
|
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
|
||||||
|
|
|
@ -18,11 +18,7 @@ class Entry_u_boot(Entry_blob):
|
||||||
to relocate itself at runtime. The binary typically includes a device tree
|
to relocate itself at runtime. The binary typically includes a device tree
|
||||||
blob at the end of it.
|
blob at the end of it.
|
||||||
|
|
||||||
U-Boot can access binman symbols at runtime. See:
|
U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (fdt)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
|
||||||
|
|
||||||
Note that this entry is automatically replaced with u-boot-expanded unless
|
Note that this entry is automatically replaced with u-boot-expanded unless
|
||||||
--no-expanded is used or the node has a 'no-expanded' property.
|
--no-expanded is used or the node has a 'no-expanded' property.
|
||||||
|
|
|
@ -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.
|
to run from the correct address if direct flash execution is possible (e.g.
|
||||||
on x86 devices).
|
on x86 devices).
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
in the binman README for more information.
|
||||||
|
|
||||||
|
@ -36,7 +34,6 @@ class Entry_u_boot_spl(Entry_blob):
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
super().__init__(section, etype, node, auto_write_symbols=True)
|
super().__init__(section, etype, node, auto_write_symbols=True)
|
||||||
self.elf_fname = 'spl/u-boot-spl'
|
self.elf_fname = 'spl/u-boot-spl'
|
||||||
self.auto_write_symbols = True
|
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return 'spl/u-boot-spl.bin'
|
return 'spl/u-boot-spl.bin'
|
||||||
|
|
|
@ -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
|
expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
|
||||||
u-boot-spl-dtb
|
u-boot-spl-dtb
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
in the binman README for more information.
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,7 @@ class Entry_u_boot_tpl(Entry_blob):
|
||||||
address in SRAM, or written to run from the correct address if direct
|
address in SRAM, or written to run from the correct address if direct
|
||||||
flash execution is possible (e.g. on x86 devices).
|
flash execution is possible (e.g. on x86 devices).
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
in the binman README for more information.
|
||||||
|
|
||||||
|
|
|
@ -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
|
expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
|
||||||
u-boot-tpl-dtb
|
u-boot-tpl-dtb
|
||||||
|
|
||||||
TPL can access binman symbols at runtime. See:
|
TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
in the binman README for more information.
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,7 @@ class Entry_u_boot_vpl(Entry_blob):
|
||||||
address in SRAM, or written to run from the correct address if direct
|
address in SRAM, or written to run from the correct address if direct
|
||||||
flash execution is possible (e.g. on x86 devices).
|
flash execution is possible (e.g. on x86 devices).
|
||||||
|
|
||||||
SPL can access binman symbols at runtime. See:
|
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
in the binman README for more information.
|
||||||
|
|
||||||
|
|
|
@ -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
|
expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
|
||||||
u-boot-vpl-dtb
|
u-boot-vpl-dtb
|
||||||
|
|
||||||
VPL can access binman symbols at runtime. See:
|
VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||||
|
|
||||||
'Access to binman entry offsets at run time (symbols)'
|
|
||||||
|
|
||||||
in the binman README for more information.
|
|
||||||
|
|
||||||
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
|
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.
|
binman uses that to look up symbols to write into the VPL binary.
|
||||||
|
|
|
@ -112,6 +112,8 @@ REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
|
||||||
# Supported compression bintools
|
# Supported compression bintools
|
||||||
COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
|
COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
|
||||||
|
|
||||||
|
TEE_ADDR = 0x5678
|
||||||
|
|
||||||
class TestFunctional(unittest.TestCase):
|
class TestFunctional(unittest.TestCase):
|
||||||
"""Functional tests for binman
|
"""Functional tests for binman
|
||||||
|
|
||||||
|
@ -219,6 +221,9 @@ class TestFunctional(unittest.TestCase):
|
||||||
TestFunctional._MakeInputFile('tee.elf',
|
TestFunctional._MakeInputFile('tee.elf',
|
||||||
tools.read_file(cls.ElfTestFile('elf_sections')))
|
tools.read_file(cls.ElfTestFile('elf_sections')))
|
||||||
|
|
||||||
|
# Newer OP_TEE file in v1 binary format
|
||||||
|
cls.make_tee_bin('tee.bin')
|
||||||
|
|
||||||
cls.comp_bintools = {}
|
cls.comp_bintools = {}
|
||||||
for name in COMP_BINTOOLS:
|
for name in COMP_BINTOOLS:
|
||||||
cls.comp_bintools[name] = bintool.Bintool.create(name)
|
cls.comp_bintools[name] = bintool.Bintool.create(name)
|
||||||
|
@ -644,6 +649,14 @@ class TestFunctional(unittest.TestCase):
|
||||||
def ElfTestFile(cls, fname):
|
def ElfTestFile(cls, fname):
|
||||||
return os.path.join(cls._elf_testdir, 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):
|
def AssertInList(self, grep_list, target):
|
||||||
"""Assert that at least one of a list of things is in a 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',
|
'Cannot write symbols to an ELF file without Python elftools',
|
||||||
str(exc.exception))
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -94,9 +94,6 @@ class Image(section.Entry_section):
|
||||||
|
|
||||||
def ReadNode(self):
|
def ReadNode(self):
|
||||||
super().ReadNode()
|
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.allow_repack = fdt_util.GetBool(self._node, 'allow-repack')
|
||||||
self._symlink = fdt_util.GetString(self._node, 'symlink')
|
self._symlink = fdt_util.GetString(self._node, 'symlink')
|
||||||
|
|
||||||
|
|
29
tools/binman/test/261_section_fname.dts
Normal file
29
tools/binman/test/261_section_fname.dts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
pad-byte = <0x26>;
|
||||||
|
size = <0x20>;
|
||||||
|
section@0 {
|
||||||
|
size = <0x10>;
|
||||||
|
pad-byte = <0x21>;
|
||||||
|
pad-before = <2>;
|
||||||
|
pad-after = <3>;
|
||||||
|
|
||||||
|
section {
|
||||||
|
filename = "outfile.bin";
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
section@1 {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
20
tools/binman/test/262_absent.dts
Normal file
20
tools/binman/test/262_absent.dts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
_testing {
|
||||||
|
set-to-absent;
|
||||||
|
};
|
||||||
|
|
||||||
|
u-boot-img {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
22
tools/binman/test/263_tee_os_opt.dts
Normal file
22
tools/binman/test/263_tee_os_opt.dts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
tee-os {
|
||||||
|
/*
|
||||||
|
* this results in nothing being added since only the
|
||||||
|
* .bin format is supported by this etype, unless it is
|
||||||
|
* part of a FIT
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
u-boot-img {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
33
tools/binman/test/264_tee_os_opt_fit.dts
Normal file
33
tools/binman/test/264_tee_os_opt_fit.dts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
fit {
|
||||||
|
description = "test-desc";
|
||||||
|
#address-cells = <1>;
|
||||||
|
fit,fdt-list = "of-list";
|
||||||
|
|
||||||
|
images {
|
||||||
|
@tee-SEQ {
|
||||||
|
fit,operation = "split-elf";
|
||||||
|
description = "TEE";
|
||||||
|
type = "tee";
|
||||||
|
arch = "arm64";
|
||||||
|
os = "tee";
|
||||||
|
compression = "none";
|
||||||
|
fit,load;
|
||||||
|
fit,entry;
|
||||||
|
fit,data;
|
||||||
|
|
||||||
|
tee-os {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
40
tools/binman/test/265_tee_os_opt_fit_bad.dts
Normal file
40
tools/binman/test/265_tee_os_opt_fit_bad.dts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
fit {
|
||||||
|
description = "test-desc";
|
||||||
|
#address-cells = <1>;
|
||||||
|
fit,fdt-list = "of-list";
|
||||||
|
|
||||||
|
images {
|
||||||
|
@tee-SEQ {
|
||||||
|
fit,operation = "split-elf";
|
||||||
|
description = "TEE";
|
||||||
|
type = "tee";
|
||||||
|
arch = "arm64";
|
||||||
|
os = "tee";
|
||||||
|
compression = "none";
|
||||||
|
fit,load;
|
||||||
|
fit,entry;
|
||||||
|
fit,data;
|
||||||
|
|
||||||
|
tee-os {
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mess up the ELF data by adding
|
||||||
|
* another bit of data at the end
|
||||||
|
*/
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
21
tools/binman/test/266_blob_ext_opt.dts
Normal file
21
tools/binman/test/266_blob_ext_opt.dts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
ok {
|
||||||
|
type = "blob-ext";
|
||||||
|
filename = "refcode.bin";
|
||||||
|
};
|
||||||
|
|
||||||
|
missing {
|
||||||
|
type = "blob-ext";
|
||||||
|
filename = "missing.bin";
|
||||||
|
optional;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
16
tools/binman/test/267_section_inner.dts
Normal file
16
tools/binman/test/267_section_inner.dts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
section {
|
||||||
|
size = <0x10>;
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
19
tools/binman/test/268_null.dts
Normal file
19
tools/binman/test/268_null.dts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
pad-byte = <0xff>;
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
null {
|
||||||
|
size = <4>;
|
||||||
|
};
|
||||||
|
u-boot-img {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
21
tools/binman/test/269_overlap.dts
Normal file
21
tools/binman/test/269_overlap.dts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
inset {
|
||||||
|
type = "fill";
|
||||||
|
fill-byte = [61];
|
||||||
|
offset = <1>;
|
||||||
|
size = <2>;
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
24
tools/binman/test/270_overlap_null.dts
Normal file
24
tools/binman/test/270_overlap_null.dts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
section {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
null {
|
||||||
|
offset = <1>;
|
||||||
|
size = <2>;
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fmap {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
21
tools/binman/test/271_overlap_bad.dts
Normal file
21
tools/binman/test/271_overlap_bad.dts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
inset {
|
||||||
|
type = "fill";
|
||||||
|
fill-byte = [61];
|
||||||
|
offset = <0x10>;
|
||||||
|
size = <2>;
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
19
tools/binman/test/272_overlap_no_size.dts
Normal file
19
tools/binman/test/272_overlap_no_size.dts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
inset {
|
||||||
|
type = "fill";
|
||||||
|
fill-byte = [61];
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
24
tools/binman/test/273_blob_symbol.dts
Normal file
24
tools/binman/test/273_blob_symbol.dts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
blob {
|
||||||
|
filename = "blob_syms.bin";
|
||||||
|
write-symbols;
|
||||||
|
elf-filename = "blob_syms";
|
||||||
|
elf-base-sym = "__my_start_sym";
|
||||||
|
};
|
||||||
|
|
||||||
|
inset {
|
||||||
|
type = "null";
|
||||||
|
offset = <4>;
|
||||||
|
size = <8>;
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
30
tools/binman/test/274_offset_from_elf.dts
Normal file
30
tools/binman/test/274_offset_from_elf.dts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
blob: blob {
|
||||||
|
filename = "blob_syms.bin";
|
||||||
|
elf-filename = "blob_syms";
|
||||||
|
elf-base-sym = "__my_start_sym";
|
||||||
|
};
|
||||||
|
|
||||||
|
inset {
|
||||||
|
type = "null";
|
||||||
|
offset-from-elf = <&blob>, "val3", <0>;
|
||||||
|
size = <4>;
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
|
||||||
|
inset2 {
|
||||||
|
type = "null";
|
||||||
|
offset-from-elf = <&blob>, "val3", <4>;
|
||||||
|
size = <4>;
|
||||||
|
overlap;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -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_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
|
||||||
LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
|
LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
|
||||||
LDS_EFL_SECTIONS := -T $(SRC)elf_sections.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 \
|
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 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_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)
|
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: CFLAGS += $(LDS_BINMAN_EMBED)
|
||||||
u_boot_binman_embed_sm: u_boot_binman_embed_sm.c
|
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: CFLAGS += $(LDS_EFL_SECTIONS)
|
||||||
elf_sections: elf_sections.c
|
elf_sections: elf_sections.c
|
||||||
|
|
||||||
|
|
20
tools/binman/test/blob_syms.c
Normal file
20
tools/binman/test/blob_syms.c
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Google, Inc
|
||||||
|
*
|
||||||
|
* Simple program to create some binman symbols. This is used by binman tests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef unsigned long ulong;
|
||||||
|
|
||||||
|
#include <linux/kconfig.h>
|
||||||
|
#include <binman_sym.h>
|
||||||
|
|
||||||
|
DECLARE_BINMAN_MAGIC_SYM;
|
||||||
|
|
||||||
|
unsigned long val1 = 123;
|
||||||
|
unsigned long val2 = 456;
|
||||||
|
binman_sym_declare(unsigned long, inset, offset);
|
||||||
|
unsigned long val3 = 789;
|
||||||
|
unsigned long val4 = 999;
|
||||||
|
binman_sym_declare(unsigned long, inset, size);
|
30
tools/binman/test/blob_syms.lds
Normal file
30
tools/binman/test/blob_syms.lds
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Google, Inc
|
||||||
|
*/
|
||||||
|
|
||||||
|
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||||
|
OUTPUT_ARCH(i386)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x00000010;
|
||||||
|
_start = .;
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
__my_start_sym = .;
|
||||||
|
*(.text*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
.binman_sym_table : {
|
||||||
|
__binman_sym_start = .;
|
||||||
|
KEEP(*(SORT(.binman_sym*)));
|
||||||
|
__binman_sym_end = .;
|
||||||
|
}
|
||||||
|
.interp : { *(.interp*) }
|
||||||
|
|
||||||
|
}
|
|
@ -281,6 +281,34 @@ def GetPhandleList(node, propname):
|
||||||
value = [value]
|
value = [value]
|
||||||
return [fdt32_to_cpu(v) for v in 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):
|
def GetDatatype(node, propname, datatype):
|
||||||
"""Get a value of a given type from a property
|
"""Get a value of a given type from a property
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-reloc;
|
||||||
compatible = "source";
|
compatible = "source";
|
||||||
clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
|
clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
|
||||||
|
phandle-name-offset = <&phandle_2>, "fred", <123>;
|
||||||
};
|
};
|
||||||
|
|
||||||
phandle-source2 {
|
phandle-source2 {
|
||||||
|
|
|
@ -929,6 +929,7 @@ U_BOOT_DRVINFO(spl_test) = {
|
||||||
self._check_strings(HEADER + '''
|
self._check_strings(HEADER + '''
|
||||||
struct dtd_source {
|
struct dtd_source {
|
||||||
\tstruct phandle_2_arg clocks[4];
|
\tstruct phandle_2_arg clocks[4];
|
||||||
|
\tunsigned char phandle_name_offset[13];
|
||||||
};
|
};
|
||||||
struct dtd_target {
|
struct dtd_target {
|
||||||
\tfdt32_t\t\tintval;
|
\tfdt32_t\t\tintval;
|
||||||
|
@ -981,6 +982,8 @@ static struct dtd_source dtv_phandle_source = {
|
||||||
\t\t\t{0, {11}},
|
\t\t\t{0, {11}},
|
||||||
\t\t\t{1, {12, 13}},
|
\t\t\t{1, {12, 13}},
|
||||||
\t\t\t{4, {}},},
|
\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) = {
|
U_BOOT_DRVINFO(phandle_source) = {
|
||||||
\t.name\t\t= "source",
|
\t.name\t\t= "source",
|
||||||
|
|
|
@ -795,6 +795,17 @@ class TestFdtUtil(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
tools.outdir= old_outdir
|
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):
|
def run_test_coverage(build_dir):
|
||||||
"""Run the tests and check that we get 100% coverage
|
"""Run the tests and check that we get 100% coverage
|
||||||
|
|
|
@ -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,
|
tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true,
|
||||||
false);
|
false);
|
||||||
if (tfd < 0)
|
if (tfd < 0) {
|
||||||
|
fprintf(stderr, "Cannot map FDT file '%s'\n", tmpfile);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (params->keydest) {
|
if (params->keydest) {
|
||||||
struct stat dest_sbuf;
|
struct stat dest_sbuf;
|
||||||
|
|
|
@ -1292,8 +1292,12 @@ int fit_add_verification_data(const char *keydir, const char *keyfile,
|
||||||
ret = fit_image_add_verification_data(keydir, keyfile, keydest,
|
ret = fit_image_add_verification_data(keydir, keyfile, keydest,
|
||||||
fit, noffset, comment, require_keys, engine_id,
|
fit, noffset, comment, require_keys, engine_id,
|
||||||
cmdname, algo_name);
|
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;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there are no keys, we can't sign configurations */
|
/* If there are no keys, we can't sign configurations */
|
||||||
|
|
1
tools/patman/.checkpatch.conf
Symbolic link
1
tools/patman/.checkpatch.conf
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../.checkpatch.conf
|
|
@ -211,7 +211,7 @@ def check_patch(fname, verbose=False, show_types=False, use_tree=False):
|
||||||
stdout: Full output of checkpatch
|
stdout: Full output of checkpatch
|
||||||
"""
|
"""
|
||||||
chk = find_check_patch()
|
chk = find_check_patch()
|
||||||
args = [chk, '--u-boot', '--strict']
|
args = [chk]
|
||||||
if not use_tree:
|
if not use_tree:
|
||||||
args.append('--no-tree')
|
args.append('--no-tree')
|
||||||
if show_types:
|
if show_types:
|
||||||
|
|
|
@ -81,14 +81,15 @@ static void outf(int level, const char *fmt, ...)
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: proftool -cds -v3 <cmd> <profdata>\n"
|
"Usage: proftool [-cmtv] <cmd> <profdata>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Commands\n"
|
"Commands\n"
|
||||||
" dump-ftrace\t\tDump out textual data in ftrace format\n"
|
" dump-ftrace\t\tDump out textual data in ftrace format\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
|
" -c <cfg>\tSpecific config file\n"
|
||||||
" -m <map>\tSpecify Systen.map 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");
|
" -v <0-4>\tSpecify verbosity\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -162,7 +163,7 @@ static int read_data(FILE *fin, void *buff, int size)
|
||||||
if (!err)
|
if (!err)
|
||||||
return 1;
|
return 1;
|
||||||
if (err != size) {
|
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 -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -495,10 +496,17 @@ static int make_ftrace(void)
|
||||||
int missing_count = 0, skip_count = 0;
|
int missing_count = 0, skip_count = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printf("# tracer: ftrace\n"
|
printf("# tracer: function\n"
|
||||||
"#\n"
|
"#\n"
|
||||||
"# TASK-PID CPU# TIMESTAMP FUNCTION\n"
|
"# entries-in-buffer/entries-written: 140080/250280 #P:4\n"
|
||||||
"# | | | | |\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++) {
|
for (i = 0, call = call_list; i < call_count; i++, call++) {
|
||||||
struct func_info *func = find_func_by_offset(call->func);
|
struct func_info *func = find_func_by_offset(call->func);
|
||||||
ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
|
ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
|
||||||
|
@ -520,7 +528,7 @@ static int make_ftrace(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
|
printf("%16s-%-5d [000] .... %lu.%06lu: ", "uboot", 1,
|
||||||
time / 1000000, time % 1000000);
|
time / 1000000, time % 1000000);
|
||||||
|
|
||||||
out_func(call->func, 0, " <- ");
|
out_func(call->func, 0, " <- ");
|
||||||
|
@ -562,23 +570,23 @@ static int prof_tool(int argc, char *const argv[],
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
const char *map_fname = "System.map";
|
const char *map_fname = "System.map";
|
||||||
const char *prof_fname = NULL;
|
const char *trace_fname = NULL;
|
||||||
const char *trace_config_fname = NULL;
|
const char *config_fname = NULL;
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
verbose = 2;
|
verbose = 2;
|
||||||
while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
|
while ((opt = getopt(argc, argv, "c:m:t:v:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 'c':
|
||||||
|
config_fname = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
map_fname = optarg;
|
map_fname = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
|
||||||
prof_fname = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
trace_config_fname = optarg;
|
trace_fname = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -594,6 +602,5 @@ int main(int argc, char *argv[])
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
debug("Debug enabled\n");
|
debug("Debug enabled\n");
|
||||||
return prof_tool(argc, argv, prof_fname, map_fname,
|
return prof_tool(argc, argv, trace_fname, map_fname, config_fname);
|
||||||
trace_config_fname);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue