u-boot/arch/arm/mach-rockchip/make_fit_atf.py
Chris Webb f05d574356 rockchip: make_fit_atf.py: Eliminate pyelftools dependency
make_fit_aft.py depends on the non-standard library pyelftools to pull
out PT_LOAD segments from ELF files. However, this is as easy to do
manually, without imposing the extra dependency on users.

Structures in the ELF file are unpacked into variables named to exactly
match the ELF spec to ensure the destructuring code is reasonably
self-documenting.

Signed-off-by: Chris Webb <chris@arachsys.com>
Reviewed-by: Andy Yan <andy.yan@rock-chips.com>
Reviewed-by: Kever Yang <Kever.yang@rock-chips.com>
2019-07-20 23:59:44 +08:00

199 lines
6 KiB
Python
Executable file

#!/usr/bin/env python
"""
# 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_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 != 0:
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 == 0:
file.write(';\n')
file.write('\t\t\tfdt = "fdt_1";\n')
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, 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)
append_fdt_node(fit_file, dtbs_file_name)
fit_file.write(DT_IMAGES_NODE_END)
append_conf_node(fit_file, dtbs_file_name, len(segments))
def generate_atf_fit_dts(fit_file_name, bl31_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, 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 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)
p_data = elf[p_offset:p_offset + p_filesz]
segments.append((index, e_entry, p_paddr, p_data))
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')
opts, args = getopt.getopt(sys.argv[1:], "o:u:b: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 == "-h":
print(__doc__)
sys.exit(2)
dtbs = args
generate_atf_fit_dts(fit_its, bl31_elf, uboot_elf, dtbs)
generate_atf_binary(bl31_elf)
if __name__ == "__main__":
main()