Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 2 | """ |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 3 | # SPDX-License-Identifier: GPL-2.0+ |
| 4 | # |
| 5 | # A script to generate FIT image source for rockchip boards |
| 6 | # with ARM Trusted Firmware |
| 7 | # and multiple device trees (given on the command line) |
| 8 | # |
| 9 | # usage: $0 <dt_name> [<dt_name> [<dt_name] ...] |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 10 | """ |
| 11 | |
| 12 | import os |
| 13 | import sys |
| 14 | import getopt |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 15 | import logging |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 16 | import struct |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 17 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 18 | DT_HEADER = """ |
Tom Rini | 10e4779 | 2018-05-06 17:58:06 -0400 | [diff] [blame] | 19 | /* |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 20 | * This is a generated file. |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 21 | */ |
| 22 | /dts-v1/; |
| 23 | |
| 24 | / { |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 25 | description = "FIT image for U-Boot with bl31 (TF-A)"; |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 26 | #address-cells = <1>; |
| 27 | |
| 28 | images { |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 29 | """ |
| 30 | |
| 31 | DT_UBOOT = """ |
Kever Yang | 29c8c74 | 2018-08-23 11:01:08 +0800 | [diff] [blame] | 32 | uboot { |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 33 | description = "U-Boot (64-bit)"; |
| 34 | data = /incbin/("u-boot-nodtb.bin"); |
| 35 | type = "standalone"; |
| 36 | os = "U-Boot"; |
| 37 | arch = "arm64"; |
| 38 | compression = "none"; |
| 39 | load = <0x%08x>; |
| 40 | }; |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 41 | |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 42 | """ |
| 43 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 44 | DT_IMAGES_NODE_END = """ }; |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 45 | |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 46 | """ |
| 47 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 48 | DT_END = "};" |
| 49 | |
| 50 | def append_bl31_node(file, atf_index, phy_addr, elf_entry): |
| 51 | # Append BL31 DT node to input FIT dts file. |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 52 | data = 'bl31_0x%08x.bin' % phy_addr |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 53 | file.write('\t\tatf_%d {\n' % atf_index) |
| 54 | file.write('\t\t\tdescription = \"ARM Trusted Firmware\";\n') |
| 55 | file.write('\t\t\tdata = /incbin/("%s");\n' % data) |
| 56 | file.write('\t\t\ttype = "firmware";\n') |
| 57 | file.write('\t\t\tarch = "arm64";\n') |
| 58 | file.write('\t\t\tos = "arm-trusted-firmware";\n') |
| 59 | file.write('\t\t\tcompression = "none";\n') |
| 60 | file.write('\t\t\tload = <0x%08x>;\n' % phy_addr) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 61 | if atf_index == 1: |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 62 | file.write('\t\t\tentry = <0x%08x>;\n' % elf_entry) |
| 63 | file.write('\t\t};\n') |
| 64 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 65 | |
| 66 | def append_fdt_node(file, dtbs): |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 67 | # Append FDT nodes. |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 68 | cnt = 1 |
| 69 | for dtb in dtbs: |
| 70 | dtname = os.path.basename(dtb) |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 71 | file.write('\t\tfdt_%d {\n' % cnt) |
| 72 | file.write('\t\t\tdescription = "%s";\n' % dtname) |
| 73 | file.write('\t\t\tdata = /incbin/("%s");\n' % dtb) |
| 74 | file.write('\t\t\ttype = "flat_dt";\n') |
| 75 | file.write('\t\t\tcompression = "none";\n') |
| 76 | file.write('\t\t};\n') |
| 77 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 78 | cnt = cnt + 1 |
| 79 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 80 | def append_conf_section(file, cnt, dtname, segments): |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 81 | file.write('\t\tconfig_%d {\n' % cnt) |
| 82 | file.write('\t\t\tdescription = "%s";\n' % dtname) |
| 83 | file.write('\t\t\tfirmware = "atf_1";\n') |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 84 | file.write('\t\t\tloadables = "uboot"') |
| 85 | if segments != 0: |
| 86 | file.write(',') |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 87 | for i in range(1, segments): |
Andy Yan | 1383386 | 2019-07-04 17:44:40 +0800 | [diff] [blame] | 88 | file.write('"atf_%d"' % (i + 1)) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 89 | if i != (segments - 1): |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 90 | file.write(',') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 91 | else: |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 92 | file.write(';\n') |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 93 | if segments == 0: |
| 94 | file.write(';\n') |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 95 | file.write('\t\t\tfdt = "fdt_1";\n') |
| 96 | file.write('\t\t};\n') |
| 97 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 98 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 99 | def append_conf_node(file, dtbs, segments): |
| 100 | # Append configeration nodes. |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 101 | cnt = 1 |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 102 | file.write('\tconfigurations {\n') |
| 103 | file.write('\t\tdefault = "config_1";\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 104 | for dtb in dtbs: |
| 105 | dtname = os.path.basename(dtb) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 106 | append_conf_section(file, cnt, dtname, segments) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 107 | cnt = cnt + 1 |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 108 | file.write('\t};\n') |
| 109 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 110 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 111 | def generate_atf_fit_dts_uboot(fit_file, uboot_file_name): |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 112 | segments = unpack_elf(uboot_file_name) |
| 113 | if len(segments) != 1: |
| 114 | raise ValueError("Invalid u-boot ELF image '%s'" % uboot_file_name) |
| 115 | index, entry, p_paddr, data = segments[0] |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 116 | fit_file.write(DT_UBOOT % p_paddr) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 117 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 118 | def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, dtbs_file_name): |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 119 | segments = unpack_elf(bl31_file_name) |
| 120 | for index, entry, paddr, data in segments: |
| 121 | append_bl31_node(fit_file, index + 1, paddr, entry) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 122 | append_fdt_node(fit_file, dtbs_file_name) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 123 | fit_file.write(DT_IMAGES_NODE_END) |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 124 | append_conf_node(fit_file, dtbs_file_name, len(segments)) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 125 | |
| 126 | def generate_atf_fit_dts(fit_file_name, bl31_file_name, uboot_file_name, dtbs_file_name): |
| 127 | # Generate FIT script for ATF image. |
| 128 | if fit_file_name != sys.stdout: |
| 129 | fit_file = open(fit_file_name, "wb") |
| 130 | else: |
| 131 | fit_file = sys.stdout |
| 132 | |
| 133 | fit_file.write(DT_HEADER) |
| 134 | generate_atf_fit_dts_uboot(fit_file, uboot_file_name) |
| 135 | generate_atf_fit_dts_bl31(fit_file, bl31_file_name, dtbs_file_name) |
| 136 | fit_file.write(DT_END) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 137 | |
| 138 | if fit_file_name != sys.stdout: |
| 139 | fit_file.close() |
| 140 | |
| 141 | def generate_atf_binary(bl31_file_name): |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 142 | for index, entry, paddr, data in unpack_elf(bl31_file_name): |
| 143 | file_name = 'bl31_0x%08x.bin' % paddr |
| 144 | with open(file_name, "wb") as atf: |
| 145 | atf.write(data) |
| 146 | |
| 147 | def unpack_elf(filename): |
| 148 | with open(filename, 'rb') as file: |
| 149 | elf = file.read() |
| 150 | if elf[0:7] != b'\x7fELF\x02\x01\x01' or elf[18:20] != b'\xb7\x00': |
| 151 | raise ValueError("Invalid arm64 ELF file '%s'" % filename) |
| 152 | |
| 153 | e_entry, e_phoff = struct.unpack_from('<2Q', elf, 0x18) |
| 154 | e_phentsize, e_phnum = struct.unpack_from('<2H', elf, 0x36) |
| 155 | segments = [] |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 156 | |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 157 | for index in range(e_phnum): |
| 158 | offset = e_phoff + e_phentsize * index |
| 159 | p_type, p_flags, p_offset = struct.unpack_from('<LLQ', elf, offset) |
| 160 | if p_type == 1: # PT_LOAD |
| 161 | p_paddr, p_filesz = struct.unpack_from('<2Q', elf, offset + 0x18) |
| 162 | p_data = elf[p_offset:p_offset + p_filesz] |
| 163 | segments.append((index, e_entry, p_paddr, p_data)) |
| 164 | return segments |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 165 | |
| 166 | def main(): |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 167 | uboot_elf = "./u-boot" |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 168 | fit_its = sys.stdout |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 169 | if "BL31" in os.environ: |
| 170 | bl31_elf=os.getenv("BL31"); |
| 171 | elif os.path.isfile("./bl31.elf"): |
| 172 | bl31_elf = "./bl31.elf" |
| 173 | else: |
| 174 | os.system("echo 'int main(){}' > bl31.c") |
| 175 | os.system("${CROSS_COMPILE}gcc -c bl31.c -o bl31.elf") |
| 176 | bl31_elf = "./bl31.elf" |
| 177 | logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) |
| 178 | logging.warning(' BL31 file bl31.elf NOT found, resulting binary is non-functional') |
| 179 | logging.warning(' Please read Building section in doc/README.rockchip') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 180 | |
| 181 | opts, args = getopt.getopt(sys.argv[1:], "o:u:b:h") |
| 182 | for opt, val in opts: |
| 183 | if opt == "-o": |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 184 | fit_its = val |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 185 | elif opt == "-u": |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 186 | uboot_elf = val |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 187 | elif opt == "-b": |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 188 | bl31_elf = val |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 189 | elif opt == "-h": |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 190 | print(__doc__) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 191 | sys.exit(2) |
| 192 | |
| 193 | dtbs = args |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 194 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 195 | generate_atf_fit_dts(fit_its, bl31_elf, uboot_elf, dtbs) |
| 196 | generate_atf_binary(bl31_elf) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 197 | |
| 198 | if __name__ == "__main__": |
| 199 | main() |