Jack Mitchell | d43d0c6 | 2019-12-10 13:07:21 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
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 | |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 66 | def append_tee_node(file, atf_index, phy_addr, elf_entry): |
| 67 | # Append TEE DT node to input FIT dts file. |
| 68 | data = 'tee_0x%08x.bin' % phy_addr |
| 69 | file.write('\t\tatf_%d {\n' % atf_index) |
| 70 | file.write('\t\t\tdescription = \"TEE\";\n') |
| 71 | file.write('\t\t\tdata = /incbin/("%s");\n' % data) |
| 72 | file.write('\t\t\ttype = "tee";\n') |
| 73 | file.write('\t\t\tarch = "arm64";\n') |
| 74 | file.write('\t\t\tos = "tee";\n') |
| 75 | file.write('\t\t\tcompression = "none";\n') |
| 76 | file.write('\t\t\tload = <0x%08x>;\n' % phy_addr) |
| 77 | file.write('\t\t\tentry = <0x%08x>;\n' % elf_entry) |
| 78 | file.write('\t\t};\n') |
| 79 | file.write('\n') |
| 80 | |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 81 | def append_fdt_node(file, dtbs): |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 82 | # Append FDT nodes. |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 83 | cnt = 1 |
| 84 | for dtb in dtbs: |
| 85 | dtname = os.path.basename(dtb) |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 86 | file.write('\t\tfdt_%d {\n' % cnt) |
| 87 | file.write('\t\t\tdescription = "%s";\n' % dtname) |
| 88 | file.write('\t\t\tdata = /incbin/("%s");\n' % dtb) |
| 89 | file.write('\t\t\ttype = "flat_dt";\n') |
| 90 | file.write('\t\t\tcompression = "none";\n') |
| 91 | file.write('\t\t};\n') |
| 92 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 93 | cnt = cnt + 1 |
| 94 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 95 | def append_conf_section(file, cnt, dtname, segments): |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 96 | file.write('\t\tconfig_%d {\n' % cnt) |
| 97 | file.write('\t\t\tdescription = "%s";\n' % dtname) |
| 98 | file.write('\t\t\tfirmware = "atf_1";\n') |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 99 | file.write('\t\t\tloadables = "uboot"') |
Heiko Stuebner | 5a98979 | 2019-09-26 21:15:15 +0200 | [diff] [blame] | 100 | if segments > 1: |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 101 | file.write(',') |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 102 | for i in range(1, segments): |
Andy Yan | 1383386 | 2019-07-04 17:44:40 +0800 | [diff] [blame] | 103 | file.write('"atf_%d"' % (i + 1)) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 104 | if i != (segments - 1): |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 105 | file.write(',') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 106 | else: |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 107 | file.write(';\n') |
Heiko Stuebner | 5a98979 | 2019-09-26 21:15:15 +0200 | [diff] [blame] | 108 | if segments <= 1: |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 109 | file.write(';\n') |
Heiko Stuebner | bf4c6c4 | 2020-01-17 21:26:04 +0100 | [diff] [blame] | 110 | file.write('\t\t\tfdt = "fdt_%d";\n' % cnt) |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 111 | file.write('\t\t};\n') |
| 112 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 113 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 114 | def append_conf_node(file, dtbs, segments): |
| 115 | # Append configeration nodes. |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 116 | cnt = 1 |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 117 | file.write('\tconfigurations {\n') |
| 118 | file.write('\t\tdefault = "config_1";\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 119 | for dtb in dtbs: |
| 120 | dtname = os.path.basename(dtb) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 121 | append_conf_section(file, cnt, dtname, segments) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 122 | cnt = cnt + 1 |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 123 | file.write('\t};\n') |
| 124 | file.write('\n') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 125 | |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 126 | def generate_atf_fit_dts_uboot(fit_file, uboot_file_name): |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 127 | segments = unpack_elf(uboot_file_name) |
| 128 | if len(segments) != 1: |
| 129 | raise ValueError("Invalid u-boot ELF image '%s'" % uboot_file_name) |
| 130 | index, entry, p_paddr, data = segments[0] |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 131 | fit_file.write(DT_UBOOT % p_paddr) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 132 | |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 133 | def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, tee_file_name, dtbs_file_name): |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 134 | segments = unpack_elf(bl31_file_name) |
| 135 | for index, entry, paddr, data in segments: |
| 136 | append_bl31_node(fit_file, index + 1, paddr, entry) |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 137 | num_segments = len(segments) |
| 138 | |
| 139 | if tee_file_name: |
| 140 | tee_segments = unpack_elf(tee_file_name) |
| 141 | for index, entry, paddr, data in tee_segments: |
| 142 | append_tee_node(fit_file, num_segments + index + 1, paddr, entry) |
| 143 | num_segments = num_segments + len(tee_segments) |
| 144 | |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 145 | append_fdt_node(fit_file, dtbs_file_name) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 146 | fit_file.write(DT_IMAGES_NODE_END) |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 147 | append_conf_node(fit_file, dtbs_file_name, num_segments) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 148 | |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 149 | def generate_atf_fit_dts(fit_file_name, bl31_file_name, tee_file_name, uboot_file_name, dtbs_file_name): |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 150 | # Generate FIT script for ATF image. |
| 151 | if fit_file_name != sys.stdout: |
| 152 | fit_file = open(fit_file_name, "wb") |
| 153 | else: |
| 154 | fit_file = sys.stdout |
| 155 | |
| 156 | fit_file.write(DT_HEADER) |
| 157 | generate_atf_fit_dts_uboot(fit_file, uboot_file_name) |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 158 | generate_atf_fit_dts_bl31(fit_file, bl31_file_name, tee_file_name, dtbs_file_name) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 159 | fit_file.write(DT_END) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 160 | |
| 161 | if fit_file_name != sys.stdout: |
| 162 | fit_file.close() |
| 163 | |
| 164 | def generate_atf_binary(bl31_file_name): |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 165 | for index, entry, paddr, data in unpack_elf(bl31_file_name): |
| 166 | file_name = 'bl31_0x%08x.bin' % paddr |
| 167 | with open(file_name, "wb") as atf: |
| 168 | atf.write(data) |
| 169 | |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 170 | def generate_tee_binary(tee_file_name): |
| 171 | if tee_file_name: |
| 172 | for index, entry, paddr, data in unpack_elf(tee_file_name): |
| 173 | file_name = 'tee_0x%08x.bin' % paddr |
| 174 | with open(file_name, "wb") as atf: |
| 175 | atf.write(data) |
| 176 | |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 177 | def unpack_elf(filename): |
| 178 | with open(filename, 'rb') as file: |
| 179 | elf = file.read() |
| 180 | if elf[0:7] != b'\x7fELF\x02\x01\x01' or elf[18:20] != b'\xb7\x00': |
| 181 | raise ValueError("Invalid arm64 ELF file '%s'" % filename) |
| 182 | |
| 183 | e_entry, e_phoff = struct.unpack_from('<2Q', elf, 0x18) |
| 184 | e_phentsize, e_phnum = struct.unpack_from('<2H', elf, 0x36) |
| 185 | segments = [] |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 186 | |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 187 | for index in range(e_phnum): |
| 188 | offset = e_phoff + e_phentsize * index |
| 189 | p_type, p_flags, p_offset = struct.unpack_from('<LLQ', elf, offset) |
| 190 | if p_type == 1: # PT_LOAD |
| 191 | p_paddr, p_filesz = struct.unpack_from('<2Q', elf, offset + 0x18) |
Heinrich Schuchardt | e30025a | 2020-09-15 03:43:29 +0200 | [diff] [blame] | 192 | if p_filesz > 0: |
| 193 | p_data = elf[p_offset:p_offset + p_filesz] |
| 194 | segments.append((index, e_entry, p_paddr, p_data)) |
Chris Webb | dd7c700 | 2019-07-16 20:52:57 +0100 | [diff] [blame] | 195 | return segments |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 196 | |
| 197 | def main(): |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 198 | uboot_elf = "./u-boot" |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 199 | fit_its = sys.stdout |
Jagan Teki | 2c2b429 | 2019-06-20 16:29:22 +0530 | [diff] [blame] | 200 | if "BL31" in os.environ: |
| 201 | bl31_elf=os.getenv("BL31"); |
| 202 | elif os.path.isfile("./bl31.elf"): |
| 203 | bl31_elf = "./bl31.elf" |
| 204 | else: |
| 205 | os.system("echo 'int main(){}' > bl31.c") |
| 206 | os.system("${CROSS_COMPILE}gcc -c bl31.c -o bl31.elf") |
| 207 | bl31_elf = "./bl31.elf" |
| 208 | logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) |
| 209 | logging.warning(' BL31 file bl31.elf NOT found, resulting binary is non-functional') |
| 210 | logging.warning(' Please read Building section in doc/README.rockchip') |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 211 | |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 212 | if "TEE" in os.environ: |
| 213 | tee_elf = os.getenv("TEE") |
| 214 | elif os.path.isfile("./tee.elf"): |
| 215 | tee_elf = "./tee.elf" |
| 216 | else: |
| 217 | tee_elf = "" |
| 218 | |
| 219 | opts, args = getopt.getopt(sys.argv[1:], "o:u:b:t:h") |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 220 | for opt, val in opts: |
| 221 | if opt == "-o": |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 222 | fit_its = val |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 223 | elif opt == "-u": |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 224 | uboot_elf = val |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 225 | elif opt == "-b": |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 226 | bl31_elf = val |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 227 | elif opt == "-t": |
| 228 | tee_elf = val |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 229 | elif opt == "-h": |
Mian Yousaf Kaukab | 9a9c245 | 2018-06-08 10:47:10 +0200 | [diff] [blame] | 230 | print(__doc__) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 231 | sys.exit(2) |
| 232 | |
| 233 | dtbs = args |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 234 | |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 235 | generate_atf_fit_dts(fit_its, bl31_elf, tee_elf, uboot_elf, dtbs) |
Christoph Muellner | a0c7ee2 | 2019-05-07 11:11:01 +0200 | [diff] [blame] | 236 | generate_atf_binary(bl31_elf) |
Heiko Stuebner | a2efb6c | 2019-10-06 20:10:21 +0200 | [diff] [blame] | 237 | generate_tee_binary(tee_elf) |
Kever Yang | 58ae215 | 2017-12-15 11:15:03 +0800 | [diff] [blame] | 238 | |
| 239 | if __name__ == "__main__": |
| 240 | main() |