Clone of official tools
Diff: targets/REALTEK_RTL8195AM.py
- Revision:
- 40:7d3fa6b99b2b
- Parent:
- 36:96847d42f010
- Child:
- 41:2a77626a4c21
--- a/targets/REALTEK_RTL8195AM.py Wed Jul 19 16:44:30 2017 -0500 +++ b/targets/REALTEK_RTL8195AM.py Tue Oct 10 16:56:30 2017 -0500 @@ -1,141 +1,276 @@ """ -mbed REALTEK_RTL8195AM elf2bin script -Copyright (c) 2011-2016 Realtek Semiconductor Corp. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +Realtek Semiconductor Corp. - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -LIBRARIES BUILD +RTL8195A elf2bin script """ import sys, array, struct, os, re, subprocess import hashlib +import shutil from tools.paths import TOOLS_BOOTLOADERS from datetime import datetime # Constant Variables -RAM2_RSVD = 0x3131373835393138 +RAM2_RSVD = 0x00000000 +RAM2_VER = 0x8195FFFF00000000 +RAM2_TAG = 0x81950001 +RAM2_SHA = '0' def write_fixed_width_string(value, width, output): - # cut string to list & reverse - line = [value[i:i+2] for i in range(0, len(value), 2)] - output.write("".join([chr(long(b, 16)) for b in line])) + # cut string to list & reverse + line = [value[i:i+2] for i in range(0, len(value), 2)] + output.write("".join([chr(long(b, 16)) for b in line])) def write_fixed_width_value(value, width, output): - # convert to string - line = format(value, '0%dx' % (width)) - if len(line) > width: - print "[ERROR] value 0x%s cannot fit width %d" % (line, width) - sys.exit(-1) - # cut string to list & reverse - line = [line[i:i+2] for i in range(0, len(line), 2)] - line.reverse() - # convert to write buffer - output.write("".join([chr(long(b, 16)) for b in line])) + # convert to string + line = format(value, '0%dx' % (width)) + if len(line) > width: + print "[ERROR] value 0x%s cannot fit width %d" % (line, width) + sys.exit(-1) + # cut string to list & reverse + line = [line[i:i+2] for i in range(0, len(line), 2)] + line.reverse() + # convert to write buffer + output.write("".join([chr(long(b, 16)) for b in line])) def append_image_file(image, output): input = open(image, "rb") output.write(input.read()) input.close() -def prepend(image, image_prepend, toolchain, info): - output = open(image_prepend, "wb") - write_fixed_width_value(info['size'], 8, output) - write_fixed_width_value(info['addr'], 8, output) - write_fixed_width_value(RAM2_RSVD, 16, output) - with open(image, "rb") as input: - if toolchain == "IAR": - input.seek(info['addr']) - output.write(input.read(info['size'])) +def write_padding_bytes(output_name, size): + current_size = os.stat(output_name).st_size + padcount = size - current_size + if padcount < 0: + print "[ERROR] image is larger than expected size" + sys.exit(-1) + output = open(output_name, "ab") + output.write('\377' * padcount) output.close() -def parse_section(toolchain, elf, section): - info = {'addr':None, 'size':0}; - if toolchain not in ["GCC_ARM", "ARM_STD", "ARM", "ARM_MICRO", "IAR"]: - print "[ERROR] unsupported toolchain " + toolchain - sys.exit(-1) - - mapfile = elf.rsplit(".", 1)[0] + ".map" - - with open(mapfile, 'r') as infile: - # Search area to parse - for line in infile: - if toolchain == "GCC_ARM": - # .image2.table 0x[00000000]30000000 0x18 - # 0x[00000000]30000000 __image2_start__ = . - # 0x[00000000]30000000 __image2_entry_func__ = . - match = re.match(r'^' + section + \ - r'\s+0x0{,8}(?P<addr>[0-9A-Fa-f]{8})\s+0x(?P<size>[0-9A-Fa-f]+).*$', line) - elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]: - # Memory Map of the image - # Load Region LR_DRAM (Base: 0x30000000, Size: 0x00006a74, Max: 0x00200000, ABSOLUTE) - # Execution Region IMAGE2_TABLE (Base: 0x30000000, Size: 0x00000018, Max: 0xffffffff, ABSOLUTE, FIXED) - # Base Addr Size Type Attr Idx E Section Name Object - # 0x30000000 0x00000004 Data RO 5257 .image2.ram.data rtl8195a_init.o - match = re.match(r'^.*Region\s+' + section + \ - r'\s+\(Base: 0x(?P<addr>[0-9A-Fa-f]{8}),\s+Size: 0x(?P<size>[0-9A-Fa-f]+), .*\)$', line) - elif toolchain == "IAR": - # Section Kind Address Size Object - # ------- ---- ------- ---- ------ - # "A3": 0x8470 - # IMAGE2 0x10006000 0x5d18 <Block> - # .ram_image2.text 0x10006000 0x5bbc <Block> - # .rodata const 0x10006000 0x14 retarget.o [17] - match = re.match(r'^\s+' + section + \ - r'\s+0x(?P<addr>[0-9A-Fa-f]{8})\s+0x(?P<size>[0-9A-Fa-f]+)\s+.*<Block>$', line) - if match: - info['addr'] = int(match.group("addr"), 16) - try: - info['size'] = int(match.group("size"), 16) - except IndexError: - print "[WARNING] cannot find the size of section " + section - return info +def sha256_checksum(filename, block_size=65536): + sha256 = hashlib.sha256() + with open(filename, 'rb') as f: + for block in iter(lambda: f.read(block_size), b''): + sha256.update(block) + return sha256.hexdigest() - print "[ERROR] cannot find the address of section " + section - return info +def get_version_by_time(): + secs = int((datetime.now()-datetime(2016,11,1)).total_seconds()) + return RAM2_VER + secs # ---------------------------- # main function # ---------------------------- -def rtl8195a_elf2bin(toolchain, image_elf, image_bin): +def prepend(image, entry, segment, image_ram2, image_ota): + + # parse input arguments + output = open(image_ram2, "wb") + + write_fixed_width_value(os.stat(image).st_size, 8, output) + write_fixed_width_value(int(entry), 8, output) + write_fixed_width_value(int(segment), 8, output) + + RAM2_SHA = sha256_checksum(image) + write_fixed_width_value(RAM2_TAG, 8, output) + write_fixed_width_value(get_version_by_time(), 16, output) + write_fixed_width_string(RAM2_SHA, 64, output) + write_fixed_width_value(RAM2_RSVD, 8, output) + + append_image_file(image, output) + output.close() + + ota = open(image_ota, "wb") + write_fixed_width_value(os.stat(image).st_size, 8, ota) + write_fixed_width_value(int(entry), 8, ota) + write_fixed_width_value(int(segment), 8, ota) + write_fixed_width_value(0xFFFFFFFF, 8, ota) + write_fixed_width_value(get_version_by_time(), 16, ota) + write_fixed_width_string(RAM2_SHA, 64, ota) + write_fixed_width_value(RAM2_RSVD, 8, ota) + + append_image_file(image, ota) + ota.close() + +def find_symbol(toolchain, mapfile, symbol): + ret = None + + HEX = '0x0{,8}(?P<addr>[0-9A-Fa-f]{8})' if toolchain == "GCC_ARM": - img2_sections = [".image2.table", ".text", ".data"] + SYM = re.compile(r'^\s+' + HEX + r'\s+' + symbol + '\r?$') elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]: - img2_sections = [".image2.table", ".text", ".data"] + SYM = re.compile(r'^\s+' + HEX + r'\s+0x[0-9A-Fa-f]{8}\s+Code.*\s+i\.' + symbol + r'\s+.*$') elif toolchain == "IAR": - # actually it's block - img2_sections = ["IMAGE2"] + SYM = re.compile(r'^' + symbol + r'\s+' + HEX + '\s+.*$') + + with open(mapfile, 'r') as infile: + for line in infile: + match = re.match(SYM, line) + if match: + ret = match.group("addr") + + if not ret: + print "[ERROR] cannot find the address of symbol " + symbol + return 0 + + return int(ret,16) | 1 + +def parse_load_segment_gcc(image_elf): + # Program Headers: + # Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + # LOAD 0x000034 0x10006000 0x10006000 0x026bc 0x026bc RW 0x8 + # LOAD 0x0026f0 0x30000000 0x30000000 0x06338 0x06338 RWE 0x4 + segment_list = [] + cmd = 'arm-none-eabi-readelf -l ' + image_elf + for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"): + if not line.startswith(" LOAD"): + continue + segment = line.split() + if len(segment) != 8: + continue + offset = int(segment[1][2:], 16) + addr = int(segment[2][2:], 16) + size = int(segment[4][2:], 16) + if addr != 0 and size != 0: + segment_list.append((offset, addr, size)) + return segment_list + +def parse_load_segment_armcc(image_elf): + # ==================================== + # + # ** Program header #2 + # + # Type : PT_LOAD (1) + # File Offset : 52 (0x34) + # Virtual Addr : 0x30000000 + # Physical Addr : 0x30000000 + # Size in file : 27260 bytes (0x6a7c) + # Size in memory: 42168 bytes (0xa4b8) + # Flags : PF_X + PF_W + PF_R + PF_ARM_ENTRY (0x80000007) + # Alignment : 8 + # + (offset, addr, size) = (0, 0, 0) + segment_list = [] + in_segment = False + cmd = 'fromelf --text -v --only=none ' + image_elf + for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"): + if line == "": + pass + elif line.startswith("** Program header"): + in_segment = True + elif in_segment == False: + pass + elif line.startswith("============"): + if addr != 0 and size != 0: + segment_list.append((offset, addr, size)) + in_segment = False + (offset, addr, size) = (0, 0, 0) + elif line.startswith(" Type"): + if not re.match(r'\s+Type\s+:\s+PT_LOAD\s.*$', line): + in_segment = False + elif line.startswith(" File Offset"): + match = re.match(r'^\s+File Offset\s+:\s+(?P<offset>\d+).*$', line) + if match: + offset = int(match.group("offset")) + elif line.startswith(" Virtual Addr"): + match = re.match(r'^\s+Virtual Addr\s+:\s+0x(?P<addr>[0-9a-f]+).*$', line) + if match: + addr = int(match.group("addr"), 16) + elif line.startswith(" Size in file"): + match = re.match(r'^\s+Size in file\s+:.*\(0x(?P<size>[0-9a-f]+)\).*$', line) + if match: + size = int(match.group("size"), 16) + return segment_list + + +def parse_load_segment_iar(image_elf): + # SEGMENTS: + # + # Type Offset Virtual Physical File Sz Mem Sz Flags Align + # ---- ------ ------- -------- ------- ------ ----- ----- + # 0: load 0x34 0x10006000 0x10006000 0x26bc 0x26bc 0x6 WR 0x8 + # 1: load 0x26f0 0x30000000 0x30000000 0x6338 0x6338 0x7 XWR 0x4 + # + # SECTIONS: + # + # Name Type Addr Offset Size Aln Lnk Inf ESz Flags + # ---- ---- ---- ------ ---- --- --- --- --- ----- + # 1: .shstrtab strtab 0xfc4d8 0x60 0x4 + # 2: .strtab strtab 0xfc538 0xbb3f 0x4 + + segment_list = [] + in_segment = False + cmd = 'ielfdumparm ' + image_elf + for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"): + if line.startswith(" SEGMENTS:"): + in_segment = True + elif in_segment == False: + pass + elif line.startswith(" SECTIONS:"): + break + elif re.match(r'^\s+\w+:\s+load\s+.*$', line): + segment = line.split() + offset = int(segment[2][2:], 16) + addr = int(segment[3][2:], 16) + size = int(segment[5][2:], 16) + if addr < 0x10007000: + continue + if addr != 0 and size != 0: + segment_list.append((offset, addr, size)) + return segment_list + +def parse_load_segment(toolchain, image_elf): + if toolchain == "GCC_ARM": + return parse_load_segment_gcc(image_elf) + elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]: + return parse_load_segment_armcc(image_elf) + elif toolchain == "IAR": + return parse_load_segment_iar(image_elf) else: - print("[error] unsupported toolchain") + toolchain - return - ram2_info = {'addr':None, 'size':0} + return [] + +def write_load_segment(image_elf, image_bin, segment): + file_elf = open(image_elf, "rb") + file_bin = open(image_bin, "wb") + for (offset, addr, size) in segment: + file_elf.seek(offset) + # write image header - size & addr + write_fixed_width_value(addr, 8, file_bin) + write_fixed_width_value(size, 8, file_bin) + # write load segment + file_bin.write(file_elf.read(size)) + delta = size % 4 + if delta != 0: + padding = 4 - delta + write_fixed_width_value(0x0, padding * 2, file_bin) + file_bin.close() + file_elf.close() + +# ---------------------------- +# main function +# ---------------------------- +def rtl8195a_elf2bin(t_self, image_elf, image_bin): + # remove target binary file/path + if os.path.isfile(image_bin): + os.remove(image_bin) + else: + shutil.rmtree(image_bin) + + segment = parse_load_segment(t_self.name, image_elf) + write_load_segment(image_elf, image_bin, segment) + image_name = os.path.splitext(image_elf)[0] + image_map = image_name + '.map' - ram1_prepend_bin = os.path.join(TOOLS_BOOTLOADERS, "REALTEK_RTL8195AM", "ram_1_prepend.bin") - ram2_prepend_bin = image_name + '-ram_2_prepend.bin' - - old_bin = image_name + '.bin' - for section in img2_sections: - section_info = parse_section(toolchain, image_elf, section) - if ram2_info['addr'] is None or ram2_info['addr'] > section_info['addr']: - ram2_info['addr'] = section_info['addr'] - ram2_info['size'] = ram2_info['size'] + section_info['size'] + ram2_ent = find_symbol(t_self.name, image_map, "PLAT_Start") + ram1_bin = os.path.join(TOOLS_BOOTLOADERS, "REALTEK_RTL8195AM", "ram_1.bin") + ram2_bin = image_name + '-ram_2.bin' + ota_bin = image_name + '-ota.bin' + prepend(image_bin, ram2_ent, len(segment), ram2_bin, ota_bin) - prepend(old_bin, ram2_prepend_bin, toolchain, ram2_info) # write output file output = open(image_bin, "wb") - append_image_file(ram1_prepend_bin, output) - append_image_file(ram2_prepend_bin, output) + append_image_file(ram1_bin, output) + append_image_file(ram2_bin, output) output.close() - # post built done -