Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers REALTEK_RTL8195AM.py Source File

REALTEK_RTL8195AM.py

00001 """
00002 Realtek Semiconductor Corp.
00003 
00004 RTL8195A elf2bin script
00005 """
00006 
00007 import sys, array, struct, os, re, subprocess
00008 import hashlib
00009 import shutil
00010 import time
00011 import binascii
00012 
00013 from tools.paths import TOOLS_BOOTLOADERS
00014 from tools.toolchains import TOOLCHAIN_PATHS
00015 
00016 # Constant Variables
00017 TAG = 0x81950001
00018 VER = 0x81950001
00019 CAMPAIGN = binascii.hexlify('FFFFFFFFFFFFFFFF')
00020 
00021 RAM2_HEADER = {
00022     'tag': 0,
00023     'ver': 0,
00024     'timestamp': 0,
00025     'size': 72,
00026     'hash': 'FF',
00027     'campaign': 'FF',
00028     'crc32': 0xFFFFFFFF,
00029 }
00030 
00031 def format_number(number, width):
00032     # convert to string
00033     line = format(number, '0%dx' % (width))
00034     if len(line) > width:
00035         print "[ERROR] 0x%s cannot fit in width %d" % (line, width)
00036         sys.exit(-1)
00037     # cut string to list & reverse
00038     line = [line[i:i+2] for i in range(0, len(line), 2)]
00039     line.reverse()
00040     return binascii.a2b_hex("".join(line))
00041 
00042 def format_string(string):
00043     return binascii.a2b_hex(string)
00044 
00045 def write_number(value, width, output):
00046     output.write(format_number(value, width))
00047 
00048 def write_string(value, width, output):
00049     output.write(format_string(value))
00050 
00051 def append_image_file(image, output):
00052     input = open(image, "rb")
00053     output.write(input.read())
00054     input.close()
00055 
00056 def write_padding_bytes(output_name, size):
00057     current_size = os.stat(output_name).st_size
00058     padcount = size - current_size
00059     if padcount < 0:
00060         print "[ERROR] image is larger than expected size"
00061         sys.exit(-1)
00062     output = open(output_name, "ab")
00063     output.write('\377' * padcount)
00064     output.close()
00065 
00066 def crc32_checksum(string):
00067     return binascii.crc32(string) & 0xFFFFFFFF
00068 
00069 def sha256_checksum(filename, block_size=65536):
00070     sha256 = hashlib.sha256()
00071     with open(filename, 'rb') as f:
00072         for block in iter(lambda: f.read(block_size), b''):
00073             sha256.update(block)
00074     return sha256.hexdigest()
00075 
00076 def epoch_timestamp():
00077     epoch = int(time.time())
00078     return epoch
00079 
00080 def find_symbol(toolchain, mapfile, symbol):
00081     ret = None
00082 
00083     HEX = '0x0{,8}(?P<addr>[0-9A-Fa-f]{8})'
00084     if toolchain == "GCC_ARM":
00085         SYM = re.compile(r'^\s+' + HEX + r'\s+' + symbol + '\r?$')
00086     elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]:
00087         SYM = re.compile(r'^\s+' + HEX + r'\s+0x[0-9A-Fa-f]{8}\s+Code.*\s+i\.' + symbol + r'\s+.*$')
00088     elif toolchain == "IAR":
00089         SYM = re.compile(r'^' + symbol + r'\s+' + HEX + '\s+.*$')
00090 
00091     with open(mapfile, 'r') as infile:
00092         for line in infile:
00093             match = re.match(SYM, line)
00094             if match:
00095                 ret = match.group("addr")
00096 
00097     if not ret:
00098         print "[ERROR] cannot find the address of symbol " + symbol
00099         return 0
00100 
00101     return int(ret,16) | 1
00102 
00103 def parse_load_segment_gcc(image_elf):
00104     # Program Headers:
00105     #   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
00106     #   LOAD           0x000034 0x10006000 0x10006000 0x026bc 0x026bc RW  0x8
00107     #   LOAD           0x0026f0 0x30000000 0x30000000 0x06338 0x06338 RWE 0x4
00108     segment_list = []
00109     cmd = os.path.join(TOOLCHAIN_PATHS['GCC_ARM'], 'arm-none-eabi-readelf')
00110     cmd = '"' + cmd + '"' + ' -l ' + image_elf
00111     for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"):
00112         if not line.startswith("  LOAD"):
00113             continue
00114         segment = line.split()
00115         if len(segment) != 8:
00116             continue
00117         offset = int(segment[1][2:], 16)
00118         addr   = int(segment[2][2:], 16)
00119         size   = int(segment[4][2:], 16)
00120         if addr != 0 and size != 0:
00121             segment_list.append((offset, addr, size))
00122     return segment_list
00123 
00124 def parse_load_segment_armcc(image_elf):
00125     # ====================================
00126     #
00127     # ** Program header #2
00128     #
00129     #     Type          : PT_LOAD (1)
00130     #     File Offset   : 52 (0x34)
00131     #     Virtual Addr  : 0x30000000
00132     #     Physical Addr : 0x30000000
00133     #     Size in file  : 27260 bytes (0x6a7c)
00134     #     Size in memory: 42168 bytes (0xa4b8)
00135     #     Flags         : PF_X + PF_W + PF_R + PF_ARM_ENTRY (0x80000007)
00136     #     Alignment     : 8
00137     #
00138     (offset, addr, size) = (0, 0, 0)
00139     segment_list = []
00140     in_segment = False
00141     cmd = os.path.join(TOOLCHAIN_PATHS['ARM'], 'bin', 'fromelf')
00142     cmd = '"' + cmd + '"' + ' --text -v --only=none ' + image_elf
00143     for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"):
00144         if line == "":
00145             pass
00146         elif line.startswith("** Program header"):
00147             in_segment = True
00148         elif in_segment == False:
00149             pass
00150         elif line.startswith("============"):
00151             if addr != 0 and size != 0:
00152                 segment_list.append((offset, addr, size))
00153             in_segment = False
00154             (offset, addr, size) = (0, 0, 0)
00155         elif line.startswith("    Type"):
00156             if not re.match(r'\s+Type\s+:\s+PT_LOAD\s.*$', line):
00157                 in_segment = False
00158         elif line.startswith("    File Offset"):
00159             match = re.match(r'^\s+File Offset\s+:\s+(?P<offset>\d+).*$', line)
00160             if match:
00161                 offset = int(match.group("offset"))
00162         elif line.startswith("    Virtual Addr"):
00163             match = re.match(r'^\s+Virtual Addr\s+:\s+0x(?P<addr>[0-9a-f]+).*$', line)
00164             if match:
00165                 addr = int(match.group("addr"), 16)
00166         elif line.startswith("    Size in file"):
00167             match = re.match(r'^\s+Size in file\s+:.*\(0x(?P<size>[0-9a-f]+)\).*$', line)
00168             if match:
00169                 size = int(match.group("size"), 16)
00170     return segment_list
00171 
00172 
00173 def parse_load_segment_iar(image_elf):
00174     #   SEGMENTS:
00175     #
00176     #      Type Offset    Virtual   Physical File Sz Mem Sz Flags   Align
00177     #      ---- ------    -------   -------- ------- ------ -----   -----
00178     #   0: load   0x34 0x10006000 0x10006000  0x26bc 0x26bc 0x6  WR   0x8
00179     #   1: load 0x26f0 0x30000000 0x30000000  0x6338 0x6338 0x7 XWR   0x4
00180     #
00181     #   SECTIONS:
00182     #
00183     #       Name            Type     Addr         Offset    Size Aln Lnk Inf  ESz Flags
00184     #       ----            ----     ----         ------    ---- --- --- ---  --- -----
00185     #    1: .shstrtab       strtab               0xfc4d8    0x60 0x4
00186     #    2: .strtab         strtab               0xfc538  0xbb3f 0x4
00187 
00188     segment_list = []
00189     in_segment = False
00190     cmd = os.path.join(TOOLCHAIN_PATHS['IAR'], 'bin', 'ielfdumparm')
00191     cmd = '"' + cmd + '"' + ' ' + image_elf
00192     for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"):
00193         if line.startswith("  SEGMENTS:"):
00194             in_segment = True
00195         elif in_segment == False:
00196             pass
00197         elif line.startswith("  SECTIONS:"):
00198             break
00199         elif re.match(r'^\s+\w+:\s+load\s+.*$', line):
00200             segment = line.split()
00201             offset = int(segment[2][2:], 16)
00202             addr   = int(segment[3][2:], 16)
00203             size   = int(segment[5][2:], 16)
00204             if addr != 0 and size != 0:
00205                 segment_list.append((offset, addr, size))
00206     return segment_list
00207 
00208 def parse_load_segment(toolchain, image_elf):
00209     if toolchain == "GCC_ARM":
00210         return parse_load_segment_gcc(image_elf)
00211     elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]:
00212         return parse_load_segment_armcc(image_elf)
00213     elif toolchain == "IAR":
00214         return parse_load_segment_iar(image_elf)
00215     else:
00216         return []
00217 
00218 def create_payload(image_elf, ram2_bin, entry, segment):
00219     file_elf = open(image_elf, "rb")
00220     file_bin = open(ram2_bin, "wb")
00221 
00222     write_number(int(entry), 8, file_bin)
00223     write_number(int(len(segment)), 8, file_bin)
00224     write_number(0xFFFFFFFF, 8, file_bin)
00225     write_number(0xFFFFFFFF, 8, file_bin)
00226 
00227     for (offset, addr, size) in segment:
00228         file_elf.seek(offset)
00229         # write image header - size & addr
00230         write_number(addr, 8, file_bin)
00231         write_number(size, 8, file_bin)
00232         # write load segment
00233         file_bin.write(file_elf.read(size))
00234         delta = size % 4
00235         if delta != 0:
00236             padding = 4 - delta
00237             write_number(0x0, padding * 2, file_bin)
00238     file_bin.close()
00239     file_elf.close()
00240 
00241 def create_daplink(image_bin, ram1_bin, ram2_bin):
00242 
00243     # remove target binary file/path
00244     if os.path.isfile(image_bin):
00245         os.remove(image_bin)
00246     else:
00247         shutil.rmtree(image_bin)
00248 
00249     RAM2_HEADER['tag'] = format_number(TAG, 8)
00250     RAM2_HEADER['ver'] = format_number(VER, 8)
00251     RAM2_HEADER['timestamp'] = format_number(epoch_timestamp(), 16)
00252     RAM2_HEADER['size'] = format_number(os.stat(ram2_bin).st_size + 72, 8)
00253     RAM2_HEADER['hash'] = format_string(sha256_checksum(ram2_bin))
00254     RAM2_HEADER['campaign'] = format_string(CAMPAIGN)
00255 
00256     output = open(image_bin, "wb")
00257     append_image_file(ram1_bin, output)
00258     append_image_file(ram2_bin, output)
00259 
00260     output.seek(0xb000)
00261     line = ""
00262     for key in ['tag', 'ver', 'timestamp', 'size', 'hash', 'campaign']:
00263         line += RAM2_HEADER[key]
00264         output.write(RAM2_HEADER[key])
00265 
00266     RAM2_HEADER['crc32'] = format_number(crc32_checksum(line), 8)
00267 
00268     output.write(RAM2_HEADER['crc32'])
00269     output.close()
00270 
00271 # ----------------------------
00272 #       main function
00273 # ----------------------------
00274 def rtl8195a_elf2bin(t_self, image_elf, image_bin):
00275 
00276     image_name = list(os.path.splitext(image_elf))[:-1]
00277     image_map = ".".join(image_name + ['map'])
00278 
00279     ram1_bin = os.path.join(TOOLS_BOOTLOADERS, "REALTEK_RTL8195AM", "ram_1.bin")
00280     ram2_bin = ".".join(image_name) + '-payload.bin'
00281 
00282     entry = find_symbol(t_self.name, image_map, "PLAT_Start")
00283     segment = parse_load_segment(t_self.name, image_elf)
00284 
00285     create_payload(image_elf, ram2_bin, entry, segment)
00286     create_daplink(image_bin, ram1_bin, ram2_bin)