Rtos API example

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