| import argparse | |
| import os | |
| from subprocess import Popen, PIPE | |
| version = "1.2" | |
| #Fixed Pattern | |
| EDBGINFO = "EDBGINFO\x05\x00\x00\x00" | |
| SKIPPATTERN = "\x53\x4B\x49\x50" | |
| MRDUMPBI = "MRDUMPBI" | |
| #Start/End Guard Eable | |
| haveStartGuard = False | |
| haveEndGuard = False | |
| #Default AP vmlinux path (for auto find function) | |
| apSymbolPathWIN = "\\\\mtksfs00\\srv_colgin_ci\\image\\SanityLoad\\" | |
| apSymbolPathLINUX = "/proj/srv_colgin_ci/image/SanityLoad/" | |
| #Default value (would be overwitten) | |
| remappingBank4 = [[0x40000000, 0x8e000000], [0x46000000, 0x84000000]] | |
| remappingBank0 = [0x00000000, 0xae000000] | |
| DRAMOffset = 0x40000000 | |
| fileOffset = 0x00004000 | |
| def ParsingArgument() : | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("-i", type=str, dest="core_dump", required=True, help="Input full ram dump path") | |
| parser.add_argument("-o", type=str, dest="output", required=True, help="Output memory dump file path") | |
| parser.add_argument("-p", "--use_mrdump_tool",type=str, dest="use_mrdump_tool", default="No", help="Set this flag \"True\" to use merdump tool to extract SYS_COREDUMP info for supporting lagacy version") | |
| parser.add_argument("-e", "--elf", type=str, default='', dest="vmlinux", help="Input vmlinux (ELF) path") | |
| parser.add_argument("-t", "--mrdump-tool", type=str, default='mrdump-gdb', dest="dump_tool_path",help="MRDUMP Tool path (ex. dump-tools-1.00/mrdump-gdb)\ | |
| https://wiki.mediatek.inc/pages/viewpage.action?pageId=58229130") | |
| return (parser.parse_args().core_dump, parser.parse_args().output, parser.parse_args().use_mrdump_tool, parser.parse_args().vmlinux, parser.parse_args().dump_tool_path) | |
| def ConvertMD2APAddress(MDAddress) : | |
| if MDAddress[-1] >> 4 == 0 or MDAddress[-1] >> 4 == 2 or MDAddress[-1] >> 4 == 3 or MDAddress[-1] >> 4 == 6 or MDAddress[-1] >> 4 == 9 : | |
| bank = 0 | |
| elif MDAddress[-1] >> 4 == 1 or MDAddress[-1] >> 4 == 7 : | |
| bank = 1 | |
| elif MDAddress[-1] >> 4 == 4 : | |
| bank = 4 | |
| else : | |
| bank = -1 | |
| intMDAddress = int.from_bytes(MDAddress[0:3], "little") | |
| if bank == 0 : | |
| APAddress = intMDAddress - remappingBank0[0] + remappingBank0[1] | |
| elif bank == 1 : | |
| APAddress = intMDAddress - remappingBank0[0] + remappingBank0[1] + 0x02000000 | |
| elif bank == 4 : | |
| if MDAddress[-1] & 15 < 6 : | |
| APAddress = intMDAddress - remappingBank4[0][0] + remappingBank4[0][1] | |
| else : | |
| APAddress = intMDAddress - remappingBank4[1][0] + remappingBank4[1][1] | |
| APAddress +=0x40000000 | |
| else : | |
| print("Can't find remapping address") | |
| APAddress = intMDAddress | |
| APAddress += (MDAddress[3] & 15) << 24 | |
| return APAddress.to_bytes(4, "little") | |
| def ParsingMIDRStartAddress(inp) : | |
| inp.seek(remappingBank4[1][1] - DRAMOffset + fileOffset) | |
| stage = 0 | |
| ch = inp.read(1) | |
| while ch : | |
| if ord(ch) == ord(EDBGINFO[stage]) : | |
| stage += 1 | |
| else : | |
| stage = 0 | |
| if stage == len(EDBGINFO) : | |
| return True | |
| ch = inp.read(1) | |
| return False | |
| def ParsingTLV(inp, outp) : | |
| global haveStartGuard, haveEndGuard | |
| typeID = inp.read(1) | |
| #By MDMP_TLV_END = 0 | |
| while ord(typeID) != 0: | |
| lens = inp.read(2) | |
| value = inp.read(int.from_bytes(lens, byteorder="little")) | |
| if int.from_bytes(value, "little") & 1 == True : | |
| haveStartGuard = True | |
| if int.from_bytes(value, "little") & 2 == True : | |
| haveEndGuard = True | |
| outp.write(typeID+lens+value) | |
| typeID = inp.read(1) | |
| lens = inp.read(2) | |
| outp.write(typeID+lens) | |
| def StartGuardCheck(inp, outp) : | |
| startGuard = inp.read(1) | |
| if startGuard != b'\xce' : | |
| return False | |
| outp.write(startGuard) | |
| return True | |
| # ToDo: when DHL add end guard, it need to add end guard check | |
| def EndGuardCheck(inp, outp) : | |
| endGuard = inp.read(1) | |
| outp.write(endGuard) | |
| return True | |
| def ProcessMemOnEMI(inp, outp, mdAddress, lens) : | |
| print("Processing mem on EMI : ") | |
| apAddress = ConvertMD2APAddress(mdAddress) | |
| print('MD address', '0x%08x'%int.from_bytes(mdAddress, "little")) | |
| print("AP address", '0x%08x'%int.from_bytes(apAddress, "little")) | |
| DRAMAddress = int.from_bytes(apAddress, "little") - DRAMOffset + fileOffset | |
| print("File offset", '0x%08x'%DRAMAddress) | |
| storeFilePointer = inp.tell() | |
| inp.seek(DRAMAddress, 0) | |
| memData = inp.read(int.from_bytes(lens, "little")) | |
| outp.write(memData) | |
| inp.seek(storeFilePointer, 0) | |
| def ParsingDumpHeader(inp, outp) : | |
| if haveStartGuard == True and StartGuardCheck(inp, outp) == False : | |
| print("Error! Start Guard Missing") | |
| exit() | |
| memType = inp.read(1) | |
| print("Mem type : ", hex(int.from_bytes(memType, "little"))) | |
| if memType == b'\xff' : | |
| endDump = inp.read(4) | |
| # end dump check | |
| if endDump != b"\x44\x45\x41\x44" : | |
| print("End Dump Pattern Error!") | |
| exit() | |
| outp.write(memType+endDump) | |
| return memType | |
| # 128 = 0b1000 0000 | |
| if ord(memType) & 128 : | |
| headerType = 1 | |
| else : | |
| headerType = 0 | |
| outp.write(memType) | |
| address = inp.read(4) | |
| outp.write(address) | |
| addressMapping = -1 | |
| if headerType == 1 : | |
| addressMapping = inp.read(4) | |
| outp.write(addressMapping) | |
| length = inp.read(2) | |
| outp.write(length) | |
| if length == b'\xff\xff' : | |
| length = inp.read(4) | |
| outp.write(length) | |
| print("Length: ", int.from_bytes(length, "little")) | |
| skip = inp.read(4) | |
| if skip == bytes(SKIPPATTERN, "ascii") : | |
| ProcessMemOnEMI(inp, outp, address, length) | |
| else : | |
| inp.seek(-4, 1) | |
| print('MD address', '0x%08x'%int.from_bytes(address, "little")) | |
| rawData = inp.read(int.from_bytes(length, "little")) | |
| outp.write(rawData) | |
| if haveEndGuard == True and EndGuardCheck(inp, outp) == False: | |
| print("Error! End Guard Missing") | |
| return memType | |
| def RebuildFullMemoryDumpFile(inputFileName, outputFileName) : | |
| inp = open(inputFileName, "rb") | |
| outp = open(outputFileName, "wb") | |
| if ParsingMIDRStartAddress(inp) == False : | |
| print("Not Found MIDR") | |
| exit() | |
| for byte in EDBGINFO : | |
| outp.write(ord(byte).to_bytes(1, "little")) | |
| ParsingTLV(inp, outp) | |
| memType = ParsingDumpHeader(inp, outp) | |
| while memType != b'\xff' : | |
| print("\n======\n") | |
| memType = ParsingDumpHeader(inp, outp) | |
| inp.close() | |
| outp.close() | |
| def GetDRAMFileOffset(inputFileName) : | |
| global fileOffset | |
| proc = Popen("readelf -l -W %s"%inputFileName, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) | |
| commandResult = proc.communicate() | |
| if commandResult[1] != b'' : | |
| print(str(proc.communicate()[1], 'utf-8')) | |
| print("%s is invalid!! Please use the correct SYS_COREDUMP file!!" %inputFileName) | |
| exit() | |
| result = commandResult[0] | |
| result = str(result, 'utf-8') | |
| SRAMPos = result.find("LOAD") | |
| DRAMPos = result.find("LOAD", SRAMPos + 1) | |
| hexStart = result.find("0x", DRAMPos) | |
| hexEnd = result.find(" ", hexStart) | |
| fileOffset = int(result[hexStart : hexEnd], 16) | |
| print("File offset : 0x%08x" %fileOffset) | |
| def MRDUMPToolParser(inputFileName, elf, dumpToolPath) : | |
| proc = Popen("%s %s %s "%(dumpToolPath, elf, inputFileName), shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) | |
| result = proc.communicate("print /x modem_sys[0].mem_layout.md_bank0.base_ap_view_phy\n\ | |
| print /x modem_sys[0].mem_layout.md_bank0.base_md_view_phy\n\ | |
| print /x modem_sys[0].mem_layout.md_bank4_noncacheable.base_ap_view_phy\n\ | |
| print /x modem_sys[0].mem_layout.md_bank4_noncacheable.base_md_view_phy\n\ | |
| print /x modem_sys[0].mem_layout.md_bank4_cacheable.base_ap_view_phy\n\ | |
| print /x modem_sys[0].mem_layout.md_bank4_cacheable.base_md_view_phy\n".encode())[0] | |
| result = str(result, 'utf-8') | |
| remappingBank0[1] = int(result[result.find("$1")+4 : result.find('\n', result.find("$1"))], 16) | |
| remappingBank0[0] = int(result[result.find("$2")+4 : result.find('\n', result.find("$2"))], 16) | |
| remappingBank4[0][1] = int(result[result.find("$3")+4 : result.find('\n', result.find("$3"))], 16) | |
| remappingBank4[0][0] = int(result[result.find("$4")+4 : result.find('\n', result.find("$4"))], 16) | |
| remappingBank4[1][1] = int(result[result.find("$5")+4 : result.find('\n', result.find("$5"))], 16) | |
| remappingBank4[1][0] = int(result[result.find("$6")+4 : result.find('\n', result.find("$6"))], 16) | |
| print("Bank0/1 \t\t MD address: 0x%08x <-> AP address 0x%08x"%(remappingBank0[0], remappingBank0[1])) | |
| print("Bank4(noncacheable) \t MD address: 0x%08x <-> AP address 0x%08x"%(remappingBank4[0][0], remappingBank4[0][1])) | |
| print("Bank4(cacheable) \t MD address: 0x%08x <-> AP address 0x%08x"%(remappingBank4[1][0], remappingBank4[1][1])) | |
| GetDRAMFileOffset(inputFileName) | |
| return | |
| def GetAPInfo(coreDumpFile) : | |
| checkInfoList = ["BRANCH_INFO=" , "VERNO=", "SUBTARGET=", "PLATFORM="] | |
| apLoadInfo = [] | |
| inp = open(coreDumpFile, "rb") | |
| for info in checkInfoList : | |
| stage = 0 | |
| tempInfo = "" | |
| wantInfo = "" | |
| ch = inp.read(1) | |
| while ch : | |
| if ord(ch) == ord(info[stage]) : | |
| stage += 1 | |
| tempInfo = tempInfo + ch.decode() | |
| else : | |
| stage = 0 | |
| tempInfo = "" | |
| if stage == len(info) : | |
| ch = inp.read(1) | |
| if (ord(ch) >= ord('A') and ord(ch) <= ord('Z')) or (ord(ch) >= ord('a') and ord(ch) <= ord('z')) : | |
| while ord(ch) != ord('\n') : | |
| wantInfo = wantInfo + ch.decode() | |
| ch = inp.read(1) | |
| apLoadInfo.append(wantInfo) | |
| break | |
| else : | |
| stage = 0 | |
| tempInfo = "" | |
| ch = inp.read(1) | |
| if len(checkInfoList) != len(apLoadInfo): | |
| return [] | |
| return apLoadInfo | |
| def AutoFindAPELF(coreDumpFile) : | |
| print ("======\nAuto find AP ELF mode...") | |
| apInfo = GetAPInfo(coreDumpFile) | |
| if len(apInfo) == 0 : | |
| print("\nCan't find AP version info in full RAM dump!\nPlease enter the vmliux path manually!") | |
| exit() | |
| print("\nBRANCH_INFO:\t%s\nVERNO:\t\t%s\nSUBTARGET:\t%s\nPLATFORM:\t%s\n" %(apInfo[0], apInfo[1], apInfo[2], apInfo[3])) | |
| vmlinuxPath = apSymbolPathLINUX + apInfo[0] + "/Symbols/" + apInfo[1] + "/" + apInfo[3] + "/" + apInfo[2] + "/vmlinux" | |
| if os.path.isfile(vmlinuxPath) == False : | |
| print("Can't find the vmlinux in %s !\nPlease update your AP version or enter the vmliux path manually!" %vmlinuxPath) | |
| exit() | |
| print("vmlinux path : " + vmlinuxPath + "\n") | |
| return vmlinuxPath | |
| # Manual input mode (for backup) | |
| def ManualInput() : | |
| bank0StartAddress = input("Please enter the AP address mapping to Bank0/1 (0x00000000) :\n") | |
| bank4MDCacheableStartAddress = input("Please enter the Bank4 cacheable MD address :\n") | |
| bank4CacheableStartAddress = input("Please enter the AP address mapping to Bank4 (cacheable) :\n") | |
| bank4UncacheableStartAddress = input("Please enter the AP address mapping to Bank4 (uncacheable) :\n") | |
| remappingBank0[1] = int(bank0StartAddress, 16) | |
| remappingBank4[1][0] = int(bank4MDCacheableStartAddress, 16) | |
| remappingBank4[1][1] = int(bank4CacheableStartAddress, 16) | |
| remappingBank4[0][1] = int(bank4UncacheableStartAddress, 16) | |
| def ParseMRDUMPBIHeader(coreDumpFile) : | |
| inp = open(coreDumpFile, "rb") | |
| stage = 0 | |
| currentPos = 1 | |
| foundMRDUMPBI = False | |
| GetDRAMFileOffset(coreDumpFile) | |
| ch = inp.read(1) | |
| # MRDUMPBI should be stored before DRAM dump | |
| while ch and currentPos <= fileOffset: | |
| # Parsing MRDUMPBI to find MD/AP remapping info | |
| if ord(ch) == ord(MRDUMPBI[stage]) : | |
| stage += 1 | |
| else : | |
| stage = 0 | |
| currentPos = currentPos + 1 | |
| if stage == len(MRDUMPBI) : | |
| # Get AP/MD address remapping info | |
| remappingBank0[1] = int.from_bytes(inp.read(8), "little") | |
| remappingBank0[0] = int.from_bytes(inp.read(8), "little") | |
| remappingBank4[1][1] = int.from_bytes(inp.read(8), "little") | |
| remappingBank4[1][0] = int.from_bytes(inp.read(8), "little") | |
| remappingBank4[0][1] = int.from_bytes(inp.read(8), "little") | |
| remappingBank4[0][0] = int.from_bytes(inp.read(8), "little") | |
| print("Bank0/1 \t\t MD address: 0x%08x <-> AP address: 0x%08x"%(remappingBank0[0], remappingBank0[1])) | |
| print("Bank4(noncacheable) \t MD address: 0x%08x <-> AP address: 0x%08x"%(remappingBank4[0][0], remappingBank4[0][1])) | |
| print("Bank4(cacheable) \t MD address: 0x%08x <-> AP address: 0x%08x"%(remappingBank4[1][0], remappingBank4[1][1])) | |
| foundMRDUMPBI = True | |
| break | |
| ch = inp.read(1) | |
| if foundMRDUMPBI == False : | |
| print("\nCan't find MRDUMPBI! The AP version doesn't provide AP/MD address remapping info!!\n\nEnter maunal input mode: \n") | |
| ManualInput() | |
| if __name__ == "__main__": | |
| print("MIDR dump post-processing script V %s"%version) | |
| inputFileName, outputFileName, useMRDumptool, elf, dumpToolPath = ParsingArgument() | |
| if useMRDumptool == "True" : | |
| # Legacy version : need mrdump tool and vmlinux file to get AP/MD address remapping | |
| if os.name != "posix" : | |
| print("\nmrdump tool only can run on Linux!") | |
| exit() | |
| # Test mrdump tool | |
| proc = Popen("%s "%dumpToolPath, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) | |
| result = proc.communicate() | |
| if str(result[1], 'utf-8') != "" : | |
| print(str(result[1], 'utf-8')) | |
| print("Please enter the correct mrdump tool path!") | |
| exit() | |
| if elf == '' : | |
| elf = AutoFindAPELF(inputFileName) | |
| print("======\nGet MD/AP address remapping information by mrdump tool...") | |
| MRDUMPToolParser(inputFileName, elf, dumpToolPath) | |
| print("\nDone!\n") | |
| else : | |
| # From V1.2 : AP write AP/MD address remapping info to SYS_COREDUMP header, we can parse header to get those info | |
| print("======\nGet MD/AP address remapping information from dump header...") | |
| ParseMRDUMPBIHeader(inputFileName) | |
| print("\nDone!\n") | |
| print("======\n\nGenerating FULL Memory Dump File...\n") | |
| RebuildFullMemoryDumpFile(inputFileName, outputFileName) | |
| print("Done!") |