Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
post_build_script.py
00001 # 00002 # DAPLink Interface Firmware 00003 # Copyright (c) 2009-2019, ARM Limited, All Rights Reserved 00004 # SPDX-License-Identifier: Apache-2.0 00005 # 00006 # Licensed under the Apache License, Version 2.0 (the "License"); you may 00007 # not use this file except in compliance with the License. 00008 # You may obtain a copy of the License at 00009 # 00010 # http://www.apache.org/licenses/LICENSE-2.0 00011 # 00012 # Unless required by applicable law or agreed to in writing, software 00013 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00014 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 # See the License for the specific language governing permissions and 00016 # limitations under the License. 00017 # 00018 00019 from __future__ import absolute_import 00020 from __future__ import print_function 00021 00022 import argparse 00023 import itertools 00024 import binascii 00025 import struct 00026 import intelhex 00027 import offset_update 00028 from os.path import dirname, join 00029 from flash_algo import PackFlashAlgo 00030 00031 VECTOR_FMT = "<7I" 00032 CHECKSUM_FMT = "<1I" 00033 CHECKSUM_OFFSET = 0x1C 00034 TARGET_INFO_OFFSET = 13*4 00035 ALIGN_PADS = 4 00036 00037 def ranges(i): 00038 for _, b in itertools.groupby(enumerate(i), lambda x_y: x_y[1] - x_y[0]): 00039 b = list(b) 00040 yield b[0][1], b[-1][1] 00041 00042 def post_build_script(input_file, output_file, board_id=None, family_id=None, bin_offset=None, flash_algo_file=None, target_ram_start=None, target_ram_end=None, flash_blob_entry="0x20000000"): 00043 output_format_file = '-'.join(filter(None, (output_file, board_id, family_id, bin_offset))) 00044 print(output_format_file) 00045 output_file_hex = output_format_file + ".hex" 00046 output_file_binary = output_format_file + ".bin" 00047 output_file_txt = output_format_file + ".txt" 00048 output_file_c = output_format_file + ".c" 00049 output_file_c_generic = join(dirname(output_file), "bootloader_image.c") 00050 output_file_legacy = output_format_file + "_legacy_0x8000.bin" 00051 output_file_legacy_5000 = output_format_file + "_legacy_0x5000.bin" 00052 output_file_legacy_txt = output_format_file + "_legacy.txt" 00053 00054 # Read in hex file 00055 new_hex_file = intelhex.IntelHex() 00056 new_hex_file.padding = 0xFF 00057 00058 if input_file.lower().endswith('.bin'): 00059 if bin_offset is not None: 00060 new_hex_file.loadbin(input_file, offset=int(bin_offset, 16)) 00061 else: 00062 new_hex_file.loadbin(input_file) 00063 else: #always assume hex format 00064 new_hex_file.fromfile(input_file, format='hex') 00065 00066 00067 # Get the starting and ending address 00068 addresses = new_hex_file.addresses() 00069 addresses.sort() 00070 start_end_pairs = list(ranges(addresses)) 00071 regions = len(start_end_pairs) 00072 assert regions == 1, ("Error - only 1 region allowed in " 00073 "hex file %i found." % regions) 00074 start, end = start_end_pairs[0] 00075 00076 pack_flash_algo = None 00077 if flash_algo_file is not None: 00078 with open(flash_algo_file, "rb") as file_handle: 00079 pack_flash_algo = PackFlashAlgo(file_handle.read()) 00080 00081 # Checksum the vector table 00082 # 00083 # Note this is only required for NXP devices but 00084 # it doesn't hurt to checksum all builds 00085 00086 # Compute a checksum on the first 7 vector nvic vectors 00087 vector_size = struct.calcsize(VECTOR_FMT) 00088 vector_data = new_hex_file.tobinarray(start=start, size=vector_size) 00089 vectors = struct.unpack(VECTOR_FMT, vector_data) 00090 assert len(vectors) == 7, "Incorrect size of %i" % len(vectors) 00091 checksum = 0 00092 for vector in vectors: 00093 checksum += vector 00094 checksum = (~checksum + 1) & 0xFFFFFFFF # Two's compliment 00095 # Write checksum back to hex 00096 csum_start = CHECKSUM_OFFSET + start 00097 csum_data = struct.pack(CHECKSUM_FMT, checksum) 00098 assert len(csum_data) == 4 00099 new_hex_file.puts(csum_start, csum_data) 00100 00101 print("board_id", board_id) 00102 print("family_id", family_id) 00103 print("bin_offset", bin_offset) 00104 if board_id is not None or family_id is not None: 00105 target_info_addr = new_hex_file.gets(start + TARGET_INFO_OFFSET, 4) 00106 target_addr_unpack = struct.unpack("<1I",target_info_addr)[0] 00107 print("board_info offset: ",hex(target_addr_unpack - start)) 00108 #family_id is in integer hex 00109 if family_id is not None: 00110 new_hex_file.puts(target_addr_unpack + 2,struct.pack('<1H',int(family_id, 16))) 00111 #board_id is in string hex 00112 if board_id is not None: 00113 new_hex_file.puts(target_addr_unpack + 4,struct.pack('4s',"%.04X" % int(board_id, 16))) 00114 if pack_flash_algo is not None: 00115 blob_header = (0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2) 00116 stack_size = 0x200 00117 region_info_fmt = '5I' 00118 region_info_total = 10 00119 target_cfg_fmt = '3I'+ region_info_fmt*region_info_total*2 + 'IHBB' 00120 sector_info_fmt = '2I' 00121 sector_info_len = len(pack_flash_algo.sector_sizes) 00122 program_target_fmt = '14I' 00123 flash_blob_entry = int(flash_blob_entry, 16) 00124 blob_pad_size = ((len(pack_flash_algo.algo_data) + ALIGN_PADS -1) // ALIGN_PADS * ALIGN_PADS) - len(pack_flash_algo.algo_data) 00125 blob_header_size = len(blob_header) * 4 00126 total_struct_size = blob_header_size + len(pack_flash_algo.algo_data) + blob_pad_size + sector_info_len*struct.calcsize(sector_info_fmt) + struct.calcsize(program_target_fmt) + struct.calcsize(target_cfg_fmt) 00127 flash_blob_addr = end + 1 - 4 - total_struct_size #make room for crc 00128 print("flash_blob offset:", hex(flash_blob_addr - start)) 00129 new_hex_file.puts(flash_blob_addr, struct.pack('<'+'I'*len(blob_header), *blob_header)) 00130 new_hex_file.puts(flash_blob_addr + blob_header_size, pack_flash_algo.algo_data + "\x00" * blob_pad_size) 00131 sector_info_addr = flash_blob_addr+blob_header_size + len(pack_flash_algo.algo_data) + blob_pad_size 00132 sector_info_arr = [] 00133 for flash_start, flash_size in pack_flash_algo.sector_sizes: 00134 sector_info_arr.append(flash_start + pack_flash_algo.flash_start) 00135 sector_info_arr.append(flash_size) 00136 print("sector_info offset:", hex(sector_info_addr - start)) 00137 new_hex_file.puts(sector_info_addr,struct.pack('<' + 'I'*len(sector_info_arr), *sector_info_arr)) 00138 program_target_addr = sector_info_addr + len(sector_info_arr)*4 00139 stack_pointer = (flash_blob_entry + blob_header_size + pack_flash_algo.rw_start + pack_flash_algo.rw_size + stack_size + 0x100 - 1) // 0x100 * 0x100 00140 print("program_target offset:", hex(program_target_addr - start)) 00141 new_hex_file.puts(program_target_addr,struct.pack('<' + program_target_fmt, 00142 pack_flash_algo.symbols['Init'] + blob_header_size + flash_blob_entry, 00143 pack_flash_algo.symbols['UnInit'] + blob_header_size + flash_blob_entry, 00144 pack_flash_algo.symbols['EraseChip'] + blob_header_size + flash_blob_entry if pack_flash_algo.symbols['EraseChip'] != 0xffffffff else 0, 00145 pack_flash_algo.symbols['EraseSector'] + blob_header_size + flash_blob_entry, 00146 pack_flash_algo.symbols['ProgramPage'] + blob_header_size + flash_blob_entry, 00147 pack_flash_algo.symbols['Verify'] + blob_header_size + flash_blob_entry if pack_flash_algo.symbols['Verify'] != 0xffffffff else 0, 00148 flash_blob_entry + 1, #BKPT : start of blob + 1 00149 flash_blob_entry + blob_header_size + pack_flash_algo.rw_start, #RSB : blob start + header + rw data offset 00150 stack_pointer, #RSP : stack pointer 00151 flash_blob_entry + 0x00000A00, #mem buffer location 00152 flash_blob_entry, #location to write prog_blob in target RAM 00153 blob_header_size + len(pack_flash_algo.algo_data) + blob_pad_size, #prog_blob size 00154 flash_blob_addr, #address of prog_blob 00155 pack_flash_algo.page_size #ram_to_flash_bytes_to_be_written 00156 )) 00157 target_cfg_addr = program_target_addr + struct.calcsize(program_target_fmt) 00158 print("target_cfg offset:", hex(target_cfg_addr - start)) 00159 if target_ram_start is None or target_ram_end is None: 00160 raise Exception("target_ram_start and target_ram_end should be defined!") 00161 first_flash_region = (pack_flash_algo.flash_start, pack_flash_algo.flash_start + pack_flash_algo.flash_size, 1, 0, program_target_addr) 00162 first_ram_region = (int(target_ram_start, 16), int(target_ram_end, 16), 0, 0, 0) 00163 emypty_region = (0, 0, 0, 0, 0) * (region_info_total -1) 00164 all_regions = first_flash_region + emypty_region + first_ram_region + emypty_region 00165 target_flags = ( 0, 0, 0, 0) #realtime board ID, family ID and erase reset flag 00166 regions_flags = all_regions + target_flags 00167 new_hex_file.puts(target_cfg_addr, struct.pack('<' + target_cfg_fmt, 00168 0x1, #script generated 00169 sector_info_addr, # Sector start and length list 00170 sector_info_len, #Sector start and length list total 00171 *regions_flags 00172 )) 00173 board_info_flag = 1 if pack_flash_algo.symbols['EraseSector'] != 0xffffffff else 0 #kEnablePageErase 00174 new_hex_file.puts(target_addr_unpack + 12,struct.pack('<1I', board_info_flag)) #always enable page erase EraseSector is a required symbol in flash algo 00175 new_hex_file.puts(target_addr_unpack + 16,struct.pack('<1I', target_cfg_addr)) 00176 00177 # CRC the entire image 00178 # 00179 # This is required for all builds 00180 00181 # Compute checksum over the range (don't include data at location of crc) 00182 size = end - start + 1 00183 crc_size = size - 4 00184 data = new_hex_file.tobinarray(start=start, size=crc_size) 00185 crc32 = binascii.crc32(data) & 0xFFFFFFFF 00186 00187 # Write CRC to the file in little endian 00188 new_hex_file[end - 3] = (crc32 >> 0) & 0xFF 00189 new_hex_file[end - 2] = (crc32 >> 8) & 0xFF 00190 new_hex_file[end - 1] = (crc32 >> 16) & 0xFF 00191 new_hex_file[end - 0] = (crc32 >> 24) & 0xFF 00192 00193 # Write out file(s) 00194 new_hex_file.tofile(output_file_hex, 'hex') 00195 new_hex_file.tofile(output_file_binary, 'bin') 00196 with open(output_file_txt, 'w') as file_handle: 00197 file_handle.write("0x%08x\r\n" % crc32) 00198 00199 # Write out data as a C array 00200 data = new_hex_file.tobinarray(start=start, size=size) 00201 data = list(bytearray(data)) 00202 output_data = ('static const unsigned int image_start = 0x%08x;\n' 00203 'static const unsigned int image_size = 0x%08x;\n' 00204 'static const char image_data[0x%08x] = {\n ' % 00205 (start, size, size)) 00206 for i, byte_val in enumerate(data): 00207 output_data += '0x%02x' % byte_val + ', ' 00208 if ((i + 1) % 0x20) == 0: 00209 output_data += '\n ' 00210 output_data += '};\n' 00211 with open(output_file_c, 'w') as file_handle: 00212 file_handle.write(output_data) 00213 with open(output_file_c_generic, 'w') as file_handle: 00214 file_handle.write(output_data) 00215 00216 # Print info on operation 00217 print("Start 0x%x, Length 0x%x, CRC32 0x%08x" % (start, size, crc32)) 00218 00219 if start == 0x8000 or start == 0x10000 or start == 0x88000 or start == 0x0800C000: 00220 if start == 0x0800C000: 00221 # Adjust for ST-Link 00222 pad_addr = start - 0x8000 00223 else: 00224 pad_addr = start - 0x3000 00225 legacy_zero = start + 7 * 4 00226 legacy_size = 4 * 4 00227 legacy_hex_file = intelhex.IntelHex(new_hex_file) 00228 for addr in range(legacy_zero, legacy_zero + legacy_size): 00229 legacy_hex_file[addr] = 0 00230 data = legacy_hex_file.tobinarray(start=start, size=crc_size) 00231 crc32 = binascii.crc32(data) & 0xFFFFFFFF 00232 # Write CRC to the file in little endian 00233 legacy_hex_file[end - 3] = (crc32 >> 0) & 0xFF 00234 legacy_hex_file[end - 2] = (crc32 >> 8) & 0xFF 00235 legacy_hex_file[end - 1] = (crc32 >> 16) & 0xFF 00236 legacy_hex_file[end - 0] = (crc32 >> 24) & 0xFF 00237 legacy_hex_file.tofile(output_file_legacy, 'bin') 00238 with open(output_file_legacy_txt, 'w') as file_handle: 00239 file_handle.write("0x%08x\r\n" % crc32) 00240 offset_update.create_padded_image(output_file_legacy, 00241 output_file_legacy_5000, 00242 start, pad_addr, 0x40) 00243 00244 if __name__ == '__main__': 00245 parser = argparse.ArgumentParser(description='Post build tool for Board ID, Family ID, Target flash algo and CRC generation') 00246 parser.add_argument("input", type=str, help="Hex or bin file to read from.") 00247 parser.add_argument("output", type=str, 00248 help="Output base file name to write crc, board_id and family_id.") 00249 parser.add_argument("--board-id", type=str, 00250 help="board id to for the target in hex") 00251 parser.add_argument("--family-id", type=str, 00252 help="family id to for the target in hex") 00253 parser.add_argument("--bin-offset", type=str, 00254 help="binary offset in hex can be supplied if input is bin") 00255 parser.add_argument("--flash-algo-file", type=str, 00256 help="Elf, axf, or flm to extract flash algo from") 00257 parser.add_argument("--target-ram-start", type=str, 00258 help="Lowest address of target RAM for flash algo in hex") 00259 parser.add_argument("--target-ram-end", type=str, 00260 help="Highest address of target RAM for flash algo in hex") 00261 parser.add_argument("--flash-blob-entry", type=str, default="0x20000000", 00262 help="Entry point of flash algo in the target") 00263 args = parser.parse_args() 00264 post_build_script(args.input, args.output, args.board_id, args.family_id, args.bin_offset, args.flash_algo_file, args.target_ram_start, args.target_ram_end, args.flash_blob_entry)
Generated on Tue Jul 12 2022 15:37:21 by
1.7.2