From a999e4c2fd188d56130273432012bec502c4ccc1 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 20 Apr 2018 11:08:48 +0300 Subject: [PATCH] add --- USDK/rtlaimage.py | 345 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 USDK/rtlaimage.py diff --git a/USDK/rtlaimage.py b/USDK/rtlaimage.py new file mode 100644 index 0000000..dec78c8 --- /dev/null +++ b/USDK/rtlaimage.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python +# (RTL8195AM/RTL8711AM/RTL8711AF/RTL8710AF) RtlImages Utility +# pvvx + +from __future__ import print_function, division +from operator import attrgetter + +import argparse +import os +import struct +import sys + +__version__ = "22.01.18" + +PYTHON2 = sys.version_info[0] < 3 # True if on pre-Python 3 + +HM_IS_HDRR = 1 +HM_IS_HDRD = 2 +HM_IS_BOOT = 4 +HM_IS_OTA = 8 +HM_IS_SRAM = 16 +HM_IS_SDRAM = 32 + +# Function to return nth byte of a bitstring +# Different behaviour on Python 2 vs 3 +if PYTHON2: + def byte(bitstr, index): + return ord(bitstr[index]) +else: + def byte(bitstr, index): + return bitstr[index] + + +class FatalError(RuntimeError): + """ + Wrapper class for runtime errors that aren't caused by internal bugs, but by + xchip responses or input content. + """ + def __init__(self, message): + RuntimeError.__init__(self, message) + + @staticmethod + def WithResult(message, result): + """ + Return a fatal error object that appends the hex values of + 'result' as a string formatted argument. + """ + message += " (result was %s)" % hexify(result) + return FatalError(message) + +class ImageSegment(object): + """ Wrapper class for a segment in an RTL image + (very similar to a section in an ELFImage also) """ + def __init__(self, addr, data, file_offs = None): + self.addr = addr + # pad all ImageSegments to at least 4 bytes length + pad_mod = len(data) % 4 + if pad_mod != 0: + data += b"\x00" * (4 - pad_mod) + self.data = data + self.file_offs = file_offs + + def copy_with_new_addr(self, new_addr): + """ Return a new ImageSegment with same data, but mapped at + a new address. """ + return ImageSegment(new_addr, self.data, 0) + + def __repr__(self): + r = "len 0x%05x load 0x%08x" % (len(self.data), self.addr) + if self.file_offs is not None: + r += " file_offs 0x%08x" % (self.file_offs) + return r + +class ELFSection(ImageSegment): + """ Wrapper class for a section in an ELF image, has a section + name as well as the common properties of an ImageSegment. """ + def __init__(self, name, addr, data, size): + super(ELFSection, self).__init__(addr, data) + self.name = name.decode("utf-8") + self.size = size + + def __repr__(self): + return "%s %s" % (self.name, super(ELFSection, self).__repr__()) + +class ELFFile(object): + SEC_TYPE_PROGBITS = 0x01 + SEC_TYPE_STRTAB = 0x03 + + def __init__(self, name): + # Load sections from the ELF file + self.name = name + try: + with open(self.name, 'rb') as f: + self._read_elf_file(f) + except: + print('Error: Not open input ELF file <%s>!' % self.name) + sys.exit(-1) + + def get_section(self, section_name): + for s in self.sections: + if s.name == section_name: + return s + raise ValueError("No section %s in ELF file" % section_name) + + def _read_elf_file(self, f): + # read the ELF file header + LEN_FILE_HEADER = 0x34 + try: + (ident,_type,machine,_version, + self.entrypoint,_phoff,shoff,_flags, + _ehsize, _phentsize,_phnum,_shentsize, + _shnum,shstrndx) = struct.unpack("<16sHHLLLLLHHHHHH", f.read(LEN_FILE_HEADER)) + except struct.error as e: + raise FatalError("Failed to read a valid ELF header from %s: %s" % (self.name, e)) + + if byte(ident, 0) != 0x7f or ident[1:4] != b'ELF': + raise FatalError("%s has invalid ELF magic header" % self.name) + if machine != 0x28: + raise FatalError("%s does not appear to be an RTL ELF file. e_machine=%04x" % (self.name, machine)) + self._read_sections(f, shoff, shstrndx, _shnum) + + def _read_sections(self, f, section_header_offs, shstrndx, shnum): + LEN_SEC_HEADER = 0x28 + f.seek(section_header_offs) +# print("%d sections found in ELF file" % shnum) + if shnum == 0 or shnum > 100: + raise FatalError("%d sections found in ELF file!" % shnum) + section_header = f.read(shnum *LEN_SEC_HEADER) + if len(section_header) == 0: + raise FatalError("No section header found at offset %04x in ELF file." % section_header_offs) + if len(section_header) != shnum *LEN_SEC_HEADER: + print('WARNING: Unexpected ELF section header length %04x is not mod-%02x' % (len(section_header), LEN_SEC_HEADER)) + + # walk through the section header and extract all sections + section_header_offsets = range(0, len(section_header), LEN_SEC_HEADER) + + def read_section_header(offs): + name_offs,sec_type,_flags,lma,sec_offs,size = struct.unpack_from(" 1: + sorted(imgsegs, key = attrgetter('addr')) + elif len(imgsegs[0].data) == 0: # file size == 0 + self.addr = imgsegs[0].addr +# print('Segment at 0x%08x,' % self.addr, 'size 0x00000000 copy to image', self.fname) + sections.remove(imgsegs[0]) + return + self.addr = imgsegs[0].addr + s = imgsegs[len(imgsegs) - 1] + self.size = s.addr + len(s.data) - self.addr +# print('Segment at 0x%08x,' % self.addr, 'size 0x%08x' % self.size, 'copy to image', self.fname) + if self.addr < self.addrl and self.addr > self.addrh: + print('Segment Address Error!') + return + if self.size: + if self.hm & HM_IS_HDRR: + self.data = struct.pack(b'!' % self.fname) + sys.exit(-1) + + def save_ota(self, f, fn, chks): + if self.size: +# print('Segment at 0x%08x,' % self.addr, 'size 0x%08x' % self.size, 'save to %s' % fn) + try: + f.write(self.data) + i = 0 + while i < len(self.data): + chks += byte(self.data, i) + i += 1 + except: + print('Error: Not write file %s!' % fn) + sys.exit(-1) + return chks + + def save_sram(self, f, fn): + if self.size: +# print('Segment at 0x%08x,' % self.addr, 'size 0x%08x' % self.size, 'save to %s' % fn) + try: + if self.hm & HM_IS_BOOT: + gap = 0x0b000 + i = len(self.data) + if i > gap: + print('Error: Segment %s is big!' % self.name) + f.write(self.data) + while i < gap: + f.write('\xff') + i += 1 + else: + f.write(self.data) + except: + print('Error: Not write file %s!' % fn) + sys.exit(-1) + +def elf2image(args): + + e = ELFFile(args.elffile) # ELFSection is a subclass of ImageSegment +# print(e.sections) + image = [xFirmwareImage('ram_1', ['.ram.start.table', '.ram_image1.text', '.ram_image1.data'], HM_IS_BOOT + HM_IS_SRAM, 0x10000bc8, 0x10070000), + xFirmwareImage('ram_2', ['.image2.start.table', '.ram_image2.text', '.ram_image2.rodata', '.ram.data'], HM_IS_OTA + HM_IS_HDRR + HM_IS_SRAM, 0x10006000, 0x10070000), + xFirmwareImage('sdram', ['.sdr_text', '.sdr_rodata', '.sdr_data'], HM_IS_OTA + HM_IS_HDRD + HM_IS_SDRAM, 0x30000000, 0x30200000)] + + img_sram_use = 0 + img_sdram_use = 0 + + for s in image: + s.load(e.sections) + if s.hm & HM_IS_SRAM: + img_sram_use += s.size + elif s.hm & HM_IS_SDRAM: + img_sdram_use += s.size + + for s in image: + if s.size: + print('Segment at 0x%08x,' % s.addr, 'size 0x%08x' % s.size, '(%s)' % s.fname) + s.save(args.outdir, None); + s.save(args.outdir, 1); + + if args.ota: + fn = args.outdir + 'ota.bin' + try: + chks = 0 + with open(fn, "wb") as f: + for s in image: + if s.hm & HM_IS_OTA: + chks = s.save_ota(f, fn, chks) + f.write(struct.pack(b'!' % fn) + sys.exit(-1) + + if args.ram_all: + if image[0].size == 0 and image[1].size == 0: + print('Error: Ram_all = 0!') + sys.exit(-1) + fn = args.outdir + 'ram_all.bin' + try: + with open(fn, "wb") as f: + for s in image: + s.save_sram(f, fn) + f.write(struct.pack(b'!' % fn) + sys.exit(-1) + + print('Images size: SRAM %u bytes, SDRAM %u bytes [%u]' % (img_sram_use, img_sdram_use, img_sram_use + img_sdram_use)) + + +def main(): + parser = argparse.ArgumentParser(description='RtlAImages Utility version %s' % __version__, prog='rtlimage') + parser.add_argument('--ram_all', '-r', action='store_true', help='Generate ram_all files') + parser.add_argument('--ota', '-a', action='store_true', help='Generate OTA files') + parser.add_argument('elffile', type=str, help='Input ELF file',) + parser.add_argument('--outdir', '-o', type=str, default='', help='Outpyt directory') + + args = parser.parse_args() + + print('RtlAImages Utility version %s' % __version__) + if args.elffile is None: + parser.print_help() + sys.exit(1) + elf2image(args) + sys.exit(0) + +if __name__ == '__main__': + try: + main() + except FatalError as e: + print('\nA fatal error occurred: %s' % e) + sys.exit(2)