#!/usr/bin/env python """ # Copyright (C) 2010 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. """ import sys import getopt def indexToName(index): D11UCODE_NAMETAG_START = 0 D11LCN0BSINITVALS24 = 1 D11LCN0INITVALS24 = 2 D11LCN1BSINITVALS24 = 3 D11LCN1INITVALS24 = 4 D11LCN2BSINITVALS24 = 5 D11LCN2INITVALS24 = 6 D11N0ABSINITVALS16 = 7 D11N0BSINITVALS16 = 8 D11N0INITVALS16 = 9 D11UCODE_OVERSIGHT16_MIMO = 10 D11UCODE_OVERSIGHT16_MIMOSZ = 11 D11UCODE_OVERSIGHT24_LCN = 12 D11UCODE_OVERSIGHT24_LCNSZ = 13 D11UCODE_OVERSIGHT_BOMMAJOR = 14 D11UCODE_OVERSIGHT_BOMMINOR = 15 namemap = { D11UCODE_NAMETAG_START : "start", D11LCN0BSINITVALS24 : "LCN0 bs initvals 24", D11LCN0INITVALS24 : "LCN0 initvals 24", D11LCN1BSINITVALS24 : "LCN1 bs initvals 24", D11LCN1INITVALS24 : "LCN1 initvals 24", D11LCN2BSINITVALS24 : "LCN2 bs initvals 24", D11LCN2INITVALS24 : "LCN2 initvals 24", D11N0ABSINITVALS16 : "N0A bs initvals 16", D11N0BSINITVALS16 : "N0 bs initvals 16", D11N0INITVALS16 : "N0 initvals 16", D11UCODE_OVERSIGHT16_MIMO : "microcode 16 MIMO", D11UCODE_OVERSIGHT16_MIMOSZ : "microcode 16 MIMO size", D11UCODE_OVERSIGHT24_LCN : "microcode 24 LCN", D11UCODE_OVERSIGHT24_LCNSZ : "microcode 24 LCN size", D11UCODE_OVERSIGHT_BOMMAJOR : "bom major", D11UCODE_OVERSIGHT_BOMMINOR : "bom minor", } try: return namemap[index] except KeyError: return "Unknown" def parseHeader(hdr_data, sortByOffset): sections = [] for i in range(0, len(hdr_data), 3 * 4): offset = ord(hdr_data[i + 0]) | (ord(hdr_data[i + 1]) << 8) |\ (ord(hdr_data[i + 2]) << 16) | (ord(hdr_data[i + 3]) << 24) length = ord(hdr_data[i + 4]) | (ord(hdr_data[i + 5]) << 8) |\ (ord(hdr_data[i + 6]) << 16) | (ord(hdr_data[i + 7]) << 24) index = ord(hdr_data[i + 8]) | (ord(hdr_data[i + 9]) << 8) |\ (ord(hdr_data[i + 10]) << 16) | (ord(hdr_data[i + 11]) << 24) sections.append( (offset, length, index) ) if sortByOffset: sections.sort(key = lambda x: x[0]) # Sort by offset else: sections.sort(key = lambda x: x[2]) # Sort by index return sections def generateHeaderData(sections): data = [] for section in sections: (offset, length, index) = section data.append(chr(offset & 0xFF)) data.append(chr((offset >> 8) & 0xFF)) data.append(chr((offset >> 16) & 0xFF)) data.append(chr((offset >> 24) & 0xFF)) data.append(chr(length & 0xFF)) data.append(chr((length >> 8) & 0xFF)) data.append(chr((length >> 16) & 0xFF)) data.append(chr((length >> 24) & 0xFF)) data.append(chr(index & 0xFF)) data.append(chr((index >> 8) & 0xFF)) data.append(chr((index >> 16) & 0xFF)) data.append(chr((index >> 24) & 0xFF)) return "".join(data) def getSectionByIndex(sections, searchIndex): for section in sections: (offset, length, index) = section if searchIndex == index: return section return None def parseHeaderFile(hdr_filepath, sortByOffset=False): try: hdr_data = file(hdr_filepath, "rb").read() except (IOError), e: print "Failed to read header file: %s" % e.strerror return None if len(hdr_data) % (3 * 4) != 0: print "Invalid header file format" return None return parseHeader(hdr_data, sortByOffset) def dumpInfo(hdr_filepath): sections = parseHeaderFile(hdr_filepath) if not sections: return 1 for section in sections: (offset, length, index) = section print "Index %2d %24s ==> offset:0x%08X length:0x%08X" %\ (index, indexToName(index), offset, length) return 0 def extractSection(hdr_filepath, bin_filepath, extractIndex, outfilePath): sections = parseHeaderFile(hdr_filepath) if not sections: return 1 section = getSectionByIndex(sections, extractIndex) if not section: print "Did not find a section with index %d" % extractIndex return 1 (offset, length, index) = section try: bin_data = file(bin_filepath, "rb").read() except (IOError), e: print "Failed to read bin file: %s" % e.strerror return 1 try: outfile = file(outfilePath, "wb") outfile.write(bin_data[offset : offset + length]) except IndexError: print "Binfile index error." return 1 except (IOError), e: print "Failed to write output file: %s" % e.strerror return 1 return 0 def mergeSection(hdr_filepath, bin_filepath, mergeIndex, mergefilePath): sections = parseHeaderFile(hdr_filepath, sortByOffset=True) if not sections: return 1 try: bin_data = file(bin_filepath, "rb").read() except (IOError), e: print "Failed to read bin file: %s" % e.strerror return 1 try: merge_data = file(mergefilePath, "rb").read() except (IOError), e: print "Failed to open merge output file: %s" % e.strerror return 1 newBin = [] newSections = [] newOffset = 0 foundIt = False for section in sections: (offset, length, index) = section if index == mergeIndex: if foundIt: print "Confused. Multiple sections with index %d?" % index return 1 foundIt = True # We overwrite this section newBin.append(merge_data) newSections.append( (newOffset, len(merge_data), index) ) newOffset += len(merge_data) else: try: newBin.append(bin_data[offset : offset + length]) except IndexError: print "Failed to read input data" return 1 newSections.append( (newOffset, length, index) ) newOffset += length if not foundIt: print "Did not find section with index %d" % mergeIndex return 1 newBin = "".join(newBin) newHdr = generateHeaderData(newSections) try: file(bin_filepath, "wb").write(newBin) file(hdr_filepath, "wb").write(newHdr) except (IOError), e: print "Failed to write bin or header file: %s" % e.strerror return 1 return 0 def usage(): print "BRCM80211 firmware converter tool" print "" print "Usage: %s [OPTIONS]" % sys.argv[0] print "" print " -H|--header FILE Use FILE as header file" print " -B|--bin FILE Use FILE as bin file" print "" print "Actions:" print " -d|--dump Dump general information" print " -x|--extract INDEX:FILE Extract the section with index INDEX to FILE" print " -m|--merge INDEX:FILE Merges FILE into the bin file stream at INDEX" print " A Merge modifies the files specified in -H and -B" print "" print " -h|--help Print this help text" def main(): opt_header = None opt_bin = None opt_action = None opt_index = None opt_outfile = None opt_mergefile = None try: (opts, args) = getopt.getopt(sys.argv[1:], "hH:B:dx:m:", [ "help", "header=", "bin=", "dump", "extract=", "merge=", ]) except getopt.GetoptError: usage() return 1 for (o, v) in opts: if o in ("-h", "--help"): usage() return 0; if o in ("-H", "--header"): opt_header = v if o in ("-B", "--bin"): opt_bin = v if o in ("-d", "--dump"): opt_action = "dump" if o in ("-x", "--extract"): opt_action = "extract" try: v = v.split(':') opt_index = int(v[0]) opt_outfile = v[1] except IndexError, ValueError: print "Invalid -x|--extract index number\n" usage() return 1 if o in ("-m", "--merge"): opt_action = "merge" try: v = v.split(':') opt_index = int(v[0]) opt_mergefile = v[1] except IndexError, ValueError: print "Invalid -m|--merge index and/or merge file name\n" usage() return 1 if not opt_action: print "No action specified\n" usage() return 1 if opt_action == "dump": if not opt_header: print "No header file specified\n" usage() return 1 return dumpInfo(opt_header) elif opt_action == "extract": if not opt_header or not opt_bin: print "No header or bin file specified\n" usage() return 1 return extractSection(opt_header, opt_bin, opt_index, opt_outfile) elif opt_action == "merge": if not opt_header or not opt_bin: print "No header or bin file specified\n" usage() return 1 return mergeSection(opt_header, opt_bin, opt_index, opt_mergefile) return 1 if __name__ == "__main__": sys.exit(main())