Clone of official tools
Diff: targets/REALTEK_RTL8195AM.py
- Revision:
- 43:2a7da56ebd24
- Parent:
- 41:2a77626a4c21
--- a/targets/REALTEK_RTL8195AM.py Mon Nov 06 13:17:14 2017 -0600 +++ b/targets/REALTEK_RTL8195AM.py Tue Sep 25 13:43:09 2018 -0500 @@ -7,33 +7,47 @@ import sys, array, struct, os, re, subprocess import hashlib import shutil +import time +import binascii +import elftools from tools.paths import TOOLS_BOOTLOADERS from tools.toolchains import TOOLCHAIN_PATHS -from datetime import datetime # Constant Variables -RAM2_RSVD = 0x00000000 -RAM2_VER = 0x8195FFFF00000000 -RAM2_TAG = 0x81950001 -RAM2_SHA = '0' +TAG = 0x81950001 +VER = 0x81950001 +CAMPAIGN = binascii.hexlify('FFFFFFFFFFFFFFFF') -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])) +RAM2_HEADER = { + 'tag': 0, + 'ver': 0, + 'timestamp': 0, + 'size': 72, + 'hash': 'FF', + 'campaign': 'FF', + 'crc32': 0xFFFFFFFF, +} -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])) +def format_number(number, width): + # convert to string + line = format(number, '0%dx' % (width)) + if len(line) > width: + print "[ERROR] 0x%s cannot fit in 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() + return binascii.a2b_hex("".join(line)) + +def format_string(string): + return binascii.a2b_hex(string) + +def write_number(value, width, output): + output.write(format_number(value, width)) + +def write_string(value, width, output): + output.write(format_string(value)) def append_image_file(image, output): input = open(image, "rb") @@ -50,6 +64,9 @@ output.write('\377' * padcount) output.close() +def crc32_checksum(string): + return binascii.crc32(string) & 0xFFFFFFFF + def sha256_checksum(filename, block_size=65536): sha256 = hashlib.sha256() with open(filename, 'rb') as f: @@ -57,42 +74,9 @@ sha256.update(block) return sha256.hexdigest() -def get_version_by_time(): - secs = int((datetime.now()-datetime(2016,11,1)).total_seconds()) - return RAM2_VER + secs - -# ---------------------------- -# main function -# ---------------------------- -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 epoch_timestamp(): + epoch = int(time.time()) + return epoch def find_symbol(toolchain, mapfile, symbol): ret = None @@ -117,164 +101,85 @@ 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 = os.path.join(TOOLCHAIN_PATHS['GCC_ARM'], 'arm-none-eabi-readelf') - cmd = '"' + cmd + '"' + ' -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 = os.path.join(TOOLCHAIN_PATHS['ARM'], 'bin', 'fromelf') - cmd = '"' + cmd + '"' + ' --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 = os.path.join(TOOLCHAIN_PATHS['IAR'], 'bin', 'ielfdumparm') - cmd = '"' + cmd + '"' + ' ' + 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_inner(image_elf): + with open(image_elf, "rb") as fd: + elffile = elftools.elf.elffile.ELFFile(fd) + for segment in elffile.iter_segments(): + offset = segment['p_offset'] + addr = segment['p_vaddr'] + size = segment['p_filesz'] + if (addr != 0 and size != 0 and segment['p_type'] == 'PT_LOAD'): + yield offset, addr, size 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: - return [] + return list(_parse_load_segment_inner(image_elf)) + +def create_payload(image_elf, ram2_bin, entry, segment): + file_elf = open(image_elf, "rb") + file_bin = open(ram2_bin, "wb") -def write_load_segment(image_elf, image_bin, segment): - file_elf = open(image_elf, "rb") - file_bin = open(image_bin, "wb") + write_number(int(entry), 8, file_bin) + write_number(int(len(segment)), 8, file_bin) + write_number(0xFFFFFFFF, 8, file_bin) + write_number(0xFFFFFFFF, 8, file_bin) + 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_number(addr, 8, file_bin) + write_number(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) + write_number(0x0, padding * 2, file_bin) file_bin.close() file_elf.close() -# ---------------------------- -# main function -# ---------------------------- -def rtl8195a_elf2bin(t_self, image_elf, image_bin): +def create_daplink(image_bin, ram1_bin, ram2_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' + RAM2_HEADER['tag'] = format_number(TAG, 8) + RAM2_HEADER['ver'] = format_number(VER, 8) + RAM2_HEADER['timestamp'] = format_number(epoch_timestamp(), 16) + RAM2_HEADER['size'] = format_number(os.stat(ram2_bin).st_size + 72, 8) + RAM2_HEADER['hash'] = format_string(sha256_checksum(ram2_bin)) + RAM2_HEADER['campaign'] = format_string(CAMPAIGN) - 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) - - # write output file output = open(image_bin, "wb") append_image_file(ram1_bin, output) append_image_file(ram2_bin, output) + + output.seek(0xb000) + line = "" + for key in ['tag', 'ver', 'timestamp', 'size', 'hash', 'campaign']: + line += RAM2_HEADER[key] + output.write(RAM2_HEADER[key]) + + RAM2_HEADER['crc32'] = format_number(crc32_checksum(line), 8) + + output.write(RAM2_HEADER['crc32']) output.close() + +# ---------------------------- +# main function +# ---------------------------- +def rtl8195a_elf2bin(t_self, image_elf, image_bin): + + image_name = list(os.path.splitext(image_elf))[:-1] + image_map = ".".join(image_name + ['map']) + + ram1_bin = os.path.join(TOOLS_BOOTLOADERS, "REALTEK_RTL8195AM", "ram_1.bin") + ram2_bin = ".".join(image_name) + '-payload.bin' + + entry = find_symbol(t_self.name, image_map, "PLAT_Start") + segment = parse_load_segment(t_self.name, image_elf) + + create_payload(image_elf, ram2_bin, entry, segment) + create_daplink(image_bin, ram1_bin, ram2_bin)