2017-02-16 09:37:24 +00:00
|
|
|
"""
|
2017-07-27 05:24:51 +00:00
|
|
|
Realtek Semiconductor Corp.
|
2017-02-16 09:37:24 +00:00
|
|
|
|
2017-07-27 05:24:51 +00:00
|
|
|
RTL8195A elf2bin script
|
2017-02-16 09:37:24 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
import sys, array, struct, os, re, subprocess
|
|
|
|
import hashlib
|
2017-08-01 07:00:40 +00:00
|
|
|
import shutil
|
2017-02-16 09:37:24 +00:00
|
|
|
|
|
|
|
from tools.paths import TOOLS_BOOTLOADERS
|
2017-09-05 04:00:07 +00:00
|
|
|
from tools.toolchains import TOOLCHAIN_PATHS
|
2017-02-16 09:37:24 +00:00
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
# Constant Variables
|
2017-07-27 05:24:51 +00:00
|
|
|
RAM2_RSVD = 0x00000000
|
|
|
|
RAM2_VER = 0x8195FFFF00000000
|
|
|
|
RAM2_TAG = 0x81950001
|
|
|
|
RAM2_SHA = '0'
|
2017-02-16 09:37:24 +00:00
|
|
|
|
2017-11-10 14:52:14 +00:00
|
|
|
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))
|
2017-02-16 09:37:24 +00:00
|
|
|
|
2017-02-24 07:21:32 +00:00
|
|
|
def append_image_file(image, output):
|
2017-07-27 05:24:51 +00:00
|
|
|
input = open(image, "rb")
|
|
|
|
output.write(input.read())
|
2017-02-16 09:37:24 +00:00
|
|
|
input.close()
|
|
|
|
|
2017-07-27 05:24:51 +00:00
|
|
|
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 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()
|
|
|
|
|
|
|
|
def get_version_by_time():
|
|
|
|
secs = int((datetime.now()-datetime(2016,11,1)).total_seconds())
|
|
|
|
return RAM2_VER + secs
|
2017-06-29 07:36:32 +00:00
|
|
|
|
2017-08-01 07:00:40 +00:00
|
|
|
# ----------------------------
|
|
|
|
# main function
|
|
|
|
# ----------------------------
|
2017-07-27 05:24:51 +00:00
|
|
|
def prepend(image, entry, segment, image_ram2, image_ota):
|
|
|
|
|
|
|
|
# parse input arguments
|
|
|
|
output = open(image_ram2, "wb")
|
|
|
|
|
2017-11-10 14:52:14 +00:00
|
|
|
write_number(os.stat(image).st_size, 8, output)
|
|
|
|
write_number(int(entry), 8, output)
|
|
|
|
write_number(int(segment), 8, output)
|
2017-07-27 05:24:51 +00:00
|
|
|
|
|
|
|
RAM2_SHA = sha256_checksum(image)
|
2017-11-10 14:52:14 +00:00
|
|
|
write_number(RAM2_TAG, 8, output)
|
|
|
|
write_number(get_version_by_time(), 16, output)
|
|
|
|
write_string(RAM2_SHA, 64, output)
|
|
|
|
write_number(RAM2_RSVD, 8, output)
|
2017-07-27 05:24:51 +00:00
|
|
|
|
|
|
|
append_image_file(image, output)
|
2017-02-16 09:37:24 +00:00
|
|
|
output.close()
|
|
|
|
|
2017-07-27 05:24:51 +00:00
|
|
|
ota = open(image_ota, "wb")
|
2017-11-10 14:52:14 +00:00
|
|
|
write_number(os.stat(image).st_size, 8, ota)
|
|
|
|
write_number(int(entry), 8, ota)
|
|
|
|
write_number(int(segment), 8, ota)
|
|
|
|
write_number(0xFFFFFFFF, 8, ota)
|
|
|
|
write_number(get_version_by_time(), 16, ota)
|
|
|
|
write_string(RAM2_SHA, 64, ota)
|
|
|
|
write_number(RAM2_RSVD, 8, ota)
|
2017-07-27 05:24:51 +00:00
|
|
|
|
|
|
|
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":
|
|
|
|
SYM = re.compile(r'^\s+' + HEX + r'\s+' + symbol + '\r?$')
|
|
|
|
elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]:
|
|
|
|
SYM = re.compile(r'^\s+' + HEX + r'\s+0x[0-9A-Fa-f]{8}\s+Code.*\s+i\.' + symbol + r'\s+.*$')
|
|
|
|
elif toolchain == "IAR":
|
|
|
|
SYM = re.compile(r'^' + symbol + r'\s+' + HEX + '\s+.*$')
|
|
|
|
|
2017-02-28 11:15:49 +00:00
|
|
|
with open(mapfile, 'r') as infile:
|
|
|
|
for line in infile:
|
2017-07-27 05:24:51 +00:00
|
|
|
match = re.match(SYM, line)
|
2017-02-28 11:15:49 +00:00
|
|
|
if match:
|
2017-07-27 05:24:51 +00:00
|
|
|
ret = match.group("addr")
|
2017-06-29 07:36:32 +00:00
|
|
|
|
2017-07-27 05:24:51 +00:00
|
|
|
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 = []
|
2017-09-05 04:00:07 +00:00
|
|
|
cmd = os.path.join(TOOLCHAIN_PATHS['GCC_ARM'], 'arm-none-eabi-readelf')
|
|
|
|
cmd = '"' + cmd + '"' + ' -l ' + image_elf
|
2017-07-27 05:24:51 +00:00
|
|
|
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
|
2017-09-05 04:00:07 +00:00
|
|
|
cmd = os.path.join(TOOLCHAIN_PATHS['ARM'], 'bin', 'fromelf')
|
|
|
|
cmd = '"' + cmd + '"' + ' --text -v --only=none ' + image_elf
|
2017-07-27 05:24:51 +00:00
|
|
|
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
|
2017-09-05 04:00:07 +00:00
|
|
|
cmd = os.path.join(TOOLCHAIN_PATHS['IAR'], 'bin', 'ielfdumparm')
|
|
|
|
cmd = '"' + cmd + '"' + ' ' + image_elf
|
2017-07-27 05:24:51 +00:00
|
|
|
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 != 0 and size != 0:
|
|
|
|
segment_list.append((offset, addr, size))
|
|
|
|
return segment_list
|
|
|
|
|
|
|
|
def parse_load_segment(toolchain, image_elf):
|
2017-02-16 09:37:24 +00:00
|
|
|
if toolchain == "GCC_ARM":
|
2017-07-27 05:24:51 +00:00
|
|
|
return parse_load_segment_gcc(image_elf)
|
2017-02-16 09:37:24 +00:00
|
|
|
elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]:
|
2017-07-27 05:24:51 +00:00
|
|
|
return parse_load_segment_armcc(image_elf)
|
2017-02-16 09:37:24 +00:00
|
|
|
elif toolchain == "IAR":
|
2017-07-27 05:24:51 +00:00
|
|
|
return parse_load_segment_iar(image_elf)
|
2017-02-16 09:37:24 +00:00
|
|
|
else:
|
2017-07-27 05:24:51 +00:00
|
|
|
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
|
2017-11-10 14:52:14 +00:00
|
|
|
write_number(addr, 8, file_bin)
|
|
|
|
write_number(size, 8, file_bin)
|
2017-07-27 05:24:51 +00:00
|
|
|
# write load segment
|
|
|
|
file_bin.write(file_elf.read(size))
|
2017-08-28 11:04:26 +00:00
|
|
|
delta = size % 4
|
|
|
|
if delta != 0:
|
|
|
|
padding = 4 - delta
|
2017-11-10 14:52:14 +00:00
|
|
|
write_number(0x0, padding * 2, file_bin)
|
2017-07-27 05:24:51 +00:00
|
|
|
file_bin.close()
|
|
|
|
file_elf.close()
|
|
|
|
|
|
|
|
# ----------------------------
|
|
|
|
# main function
|
|
|
|
# ----------------------------
|
|
|
|
def rtl8195a_elf2bin(t_self, image_elf, image_bin):
|
2017-08-01 07:00:40 +00:00
|
|
|
# remove target binary file/path
|
|
|
|
if os.path.isfile(image_bin):
|
|
|
|
os.remove(image_bin)
|
|
|
|
else:
|
|
|
|
shutil.rmtree(image_bin)
|
|
|
|
|
2017-07-27 05:24:51 +00:00
|
|
|
segment = parse_load_segment(t_self.name, image_elf)
|
|
|
|
write_load_segment(image_elf, image_bin, segment)
|
|
|
|
|
2017-02-16 09:37:24 +00:00
|
|
|
image_name = os.path.splitext(image_elf)[0]
|
2017-07-27 05:24:51 +00:00
|
|
|
image_map = image_name + '.map'
|
|
|
|
|
|
|
|
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)
|
2017-02-16 09:37:24 +00:00
|
|
|
|
|
|
|
# write output file
|
2017-02-24 07:21:32 +00:00
|
|
|
output = open(image_bin, "wb")
|
2017-07-27 05:24:51 +00:00
|
|
|
append_image_file(ram1_bin, output)
|
|
|
|
append_image_file(ram2_bin, output)
|
2017-02-16 09:37:24 +00:00
|
|
|
output.close()
|