rjw | 6c1fd8f | 2022-11-30 14:33:01 +0800 | [diff] [blame] | 1 | import argparse
|
| 2 | import os
|
| 3 | from subprocess import Popen, PIPE
|
| 4 |
|
| 5 | version = "1.2"
|
| 6 | #Fixed Pattern
|
| 7 | EDBGINFO = "EDBGINFO\x05\x00\x00\x00"
|
| 8 | SKIPPATTERN = "\x53\x4B\x49\x50"
|
| 9 | MRDUMPBI = "MRDUMPBI"
|
| 10 |
|
| 11 | #Start/End Guard Eable
|
| 12 | haveStartGuard = False
|
| 13 | haveEndGuard = False
|
| 14 |
|
| 15 | #Default AP vmlinux path (for auto find function)
|
| 16 | apSymbolPathWIN = "\\\\mtksfs00\\srv_colgin_ci\\image\\SanityLoad\\"
|
| 17 | apSymbolPathLINUX = "/proj/srv_colgin_ci/image/SanityLoad/"
|
| 18 |
|
| 19 | #Default value (would be overwitten)
|
| 20 | remappingBank4 = [[0x40000000, 0x8e000000], [0x46000000, 0x84000000]]
|
| 21 | remappingBank0 = [0x00000000, 0xae000000]
|
| 22 | DRAMOffset = 0x40000000
|
| 23 | fileOffset = 0x00004000
|
| 24 |
|
| 25 | def ParsingArgument() :
|
| 26 | parser = argparse.ArgumentParser()
|
| 27 | parser.add_argument("-i", type=str, dest="core_dump", required=True, help="Input full ram dump path")
|
| 28 | parser.add_argument("-o", type=str, dest="output", required=True, help="Output memory dump file path")
|
| 29 | 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")
|
| 30 | parser.add_argument("-e", "--elf", type=str, default='', dest="vmlinux", help="Input vmlinux (ELF) path")
|
| 31 | 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)\
|
| 32 | https://wiki.mediatek.inc/pages/viewpage.action?pageId=58229130")
|
| 33 |
|
| 34 | 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)
|
| 35 |
|
| 36 | def ConvertMD2APAddress(MDAddress) :
|
| 37 | 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 :
|
| 38 | bank = 0
|
| 39 | elif MDAddress[-1] >> 4 == 1 or MDAddress[-1] >> 4 == 7 :
|
| 40 | bank = 1
|
| 41 | elif MDAddress[-1] >> 4 == 4 :
|
| 42 | bank = 4
|
| 43 | else :
|
| 44 | bank = -1
|
| 45 |
|
| 46 | intMDAddress = int.from_bytes(MDAddress[0:3], "little")
|
| 47 |
|
| 48 | if bank == 0 :
|
| 49 | APAddress = intMDAddress - remappingBank0[0] + remappingBank0[1]
|
| 50 | elif bank == 1 :
|
| 51 | APAddress = intMDAddress - remappingBank0[0] + remappingBank0[1] + 0x02000000
|
| 52 | elif bank == 4 :
|
| 53 | if MDAddress[-1] & 15 < 6 :
|
| 54 | APAddress = intMDAddress - remappingBank4[0][0] + remappingBank4[0][1]
|
| 55 | else :
|
| 56 | APAddress = intMDAddress - remappingBank4[1][0] + remappingBank4[1][1]
|
| 57 | APAddress +=0x40000000
|
| 58 | else :
|
| 59 | print("Can't find remapping address")
|
| 60 | APAddress = intMDAddress
|
| 61 |
|
| 62 | APAddress += (MDAddress[3] & 15) << 24
|
| 63 |
|
| 64 | return APAddress.to_bytes(4, "little")
|
| 65 |
|
| 66 | def ParsingMIDRStartAddress(inp) :
|
| 67 | inp.seek(remappingBank4[1][1] - DRAMOffset + fileOffset)
|
| 68 |
|
| 69 | stage = 0
|
| 70 | ch = inp.read(1)
|
| 71 | while ch :
|
| 72 | if ord(ch) == ord(EDBGINFO[stage]) :
|
| 73 | stage += 1
|
| 74 | else :
|
| 75 | stage = 0
|
| 76 |
|
| 77 | if stage == len(EDBGINFO) :
|
| 78 | return True
|
| 79 |
|
| 80 | ch = inp.read(1)
|
| 81 |
|
| 82 | return False
|
| 83 |
|
| 84 | def ParsingTLV(inp, outp) :
|
| 85 | global haveStartGuard, haveEndGuard
|
| 86 | typeID = inp.read(1)
|
| 87 |
|
| 88 | #By MDMP_TLV_END = 0
|
| 89 | while ord(typeID) != 0:
|
| 90 | lens = inp.read(2)
|
| 91 | value = inp.read(int.from_bytes(lens, byteorder="little"))
|
| 92 |
|
| 93 | if int.from_bytes(value, "little") & 1 == True :
|
| 94 | haveStartGuard = True
|
| 95 | if int.from_bytes(value, "little") & 2 == True :
|
| 96 | haveEndGuard = True
|
| 97 |
|
| 98 | outp.write(typeID+lens+value)
|
| 99 | typeID = inp.read(1)
|
| 100 |
|
| 101 | lens = inp.read(2)
|
| 102 | outp.write(typeID+lens)
|
| 103 |
|
| 104 | def StartGuardCheck(inp, outp) :
|
| 105 | startGuard = inp.read(1)
|
| 106 |
|
| 107 | if startGuard != b'\xce' :
|
| 108 | return False
|
| 109 |
|
| 110 | outp.write(startGuard)
|
| 111 | return True
|
| 112 |
|
| 113 | # ToDo: when DHL add end guard, it need to add end guard check
|
| 114 | def EndGuardCheck(inp, outp) :
|
| 115 | endGuard = inp.read(1)
|
| 116 | outp.write(endGuard)
|
| 117 | return True
|
| 118 |
|
| 119 | def ProcessMemOnEMI(inp, outp, mdAddress, lens) :
|
| 120 | print("Processing mem on EMI : ")
|
| 121 | apAddress = ConvertMD2APAddress(mdAddress)
|
| 122 | print('MD address', '0x%08x'%int.from_bytes(mdAddress, "little"))
|
| 123 | print("AP address", '0x%08x'%int.from_bytes(apAddress, "little"))
|
| 124 | DRAMAddress = int.from_bytes(apAddress, "little") - DRAMOffset + fileOffset
|
| 125 | print("File offset", '0x%08x'%DRAMAddress)
|
| 126 | storeFilePointer = inp.tell()
|
| 127 | inp.seek(DRAMAddress, 0)
|
| 128 | memData = inp.read(int.from_bytes(lens, "little"))
|
| 129 | outp.write(memData)
|
| 130 | inp.seek(storeFilePointer, 0)
|
| 131 |
|
| 132 |
|
| 133 | def ParsingDumpHeader(inp, outp) :
|
| 134 | if haveStartGuard == True and StartGuardCheck(inp, outp) == False :
|
| 135 | print("Error! Start Guard Missing")
|
| 136 | exit()
|
| 137 |
|
| 138 | memType = inp.read(1)
|
| 139 | print("Mem type : ", hex(int.from_bytes(memType, "little")))
|
| 140 | if memType == b'\xff' :
|
| 141 | endDump = inp.read(4)
|
| 142 | # end dump check
|
| 143 | if endDump != b"\x44\x45\x41\x44" :
|
| 144 | print("End Dump Pattern Error!")
|
| 145 | exit()
|
| 146 | outp.write(memType+endDump)
|
| 147 | return memType
|
| 148 |
|
| 149 | # 128 = 0b1000 0000
|
| 150 | if ord(memType) & 128 :
|
| 151 | headerType = 1
|
| 152 | else :
|
| 153 | headerType = 0
|
| 154 | outp.write(memType)
|
| 155 |
|
| 156 | address = inp.read(4)
|
| 157 | outp.write(address)
|
| 158 | addressMapping = -1
|
| 159 |
|
| 160 | if headerType == 1 :
|
| 161 | addressMapping = inp.read(4)
|
| 162 | outp.write(addressMapping)
|
| 163 |
|
| 164 | length = inp.read(2)
|
| 165 | outp.write(length)
|
| 166 |
|
| 167 | if length == b'\xff\xff' :
|
| 168 | length = inp.read(4)
|
| 169 | outp.write(length)
|
| 170 | print("Length: ", int.from_bytes(length, "little"))
|
| 171 |
|
| 172 | skip = inp.read(4)
|
| 173 |
|
| 174 | if skip == bytes(SKIPPATTERN, "ascii") :
|
| 175 | ProcessMemOnEMI(inp, outp, address, length)
|
| 176 | else :
|
| 177 | inp.seek(-4, 1)
|
| 178 | print('MD address', '0x%08x'%int.from_bytes(address, "little"))
|
| 179 | rawData = inp.read(int.from_bytes(length, "little"))
|
| 180 | outp.write(rawData)
|
| 181 |
|
| 182 | if haveEndGuard == True and EndGuardCheck(inp, outp) == False:
|
| 183 | print("Error! End Guard Missing")
|
| 184 |
|
| 185 | return memType
|
| 186 |
|
| 187 | def RebuildFullMemoryDumpFile(inputFileName, outputFileName) :
|
| 188 | inp = open(inputFileName, "rb")
|
| 189 | outp = open(outputFileName, "wb")
|
| 190 |
|
| 191 | if ParsingMIDRStartAddress(inp) == False :
|
| 192 | print("Not Found MIDR")
|
| 193 | exit()
|
| 194 |
|
| 195 | for byte in EDBGINFO :
|
| 196 | outp.write(ord(byte).to_bytes(1, "little"))
|
| 197 |
|
| 198 | ParsingTLV(inp, outp)
|
| 199 | memType = ParsingDumpHeader(inp, outp)
|
| 200 |
|
| 201 | while memType != b'\xff' :
|
| 202 | print("\n======\n")
|
| 203 | memType = ParsingDumpHeader(inp, outp)
|
| 204 |
|
| 205 | inp.close()
|
| 206 | outp.close()
|
| 207 |
|
| 208 | def GetDRAMFileOffset(inputFileName) :
|
| 209 | global fileOffset
|
| 210 |
|
| 211 | proc = Popen("readelf -l -W %s"%inputFileName, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
| 212 | commandResult = proc.communicate()
|
| 213 |
|
| 214 | if commandResult[1] != b'' :
|
| 215 | print(str(proc.communicate()[1], 'utf-8'))
|
| 216 | print("%s is invalid!! Please use the correct SYS_COREDUMP file!!" %inputFileName)
|
| 217 | exit()
|
| 218 |
|
| 219 | result = commandResult[0]
|
| 220 | result = str(result, 'utf-8')
|
| 221 |
|
| 222 | SRAMPos = result.find("LOAD")
|
| 223 | DRAMPos = result.find("LOAD", SRAMPos + 1)
|
| 224 | hexStart = result.find("0x", DRAMPos)
|
| 225 | hexEnd = result.find(" ", hexStart)
|
| 226 | fileOffset = int(result[hexStart : hexEnd], 16)
|
| 227 |
|
| 228 | print("File offset : 0x%08x" %fileOffset)
|
| 229 |
|
| 230 | def MRDUMPToolParser(inputFileName, elf, dumpToolPath) :
|
| 231 | proc = Popen("%s %s %s "%(dumpToolPath, elf, inputFileName), shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
| 232 |
|
| 233 | result = proc.communicate("print /x modem_sys[0].mem_layout.md_bank0.base_ap_view_phy\n\
|
| 234 | print /x modem_sys[0].mem_layout.md_bank0.base_md_view_phy\n\
|
| 235 | print /x modem_sys[0].mem_layout.md_bank4_noncacheable.base_ap_view_phy\n\
|
| 236 | print /x modem_sys[0].mem_layout.md_bank4_noncacheable.base_md_view_phy\n\
|
| 237 | print /x modem_sys[0].mem_layout.md_bank4_cacheable.base_ap_view_phy\n\
|
| 238 | print /x modem_sys[0].mem_layout.md_bank4_cacheable.base_md_view_phy\n".encode())[0]
|
| 239 |
|
| 240 | result = str(result, 'utf-8')
|
| 241 | remappingBank0[1] = int(result[result.find("$1")+4 : result.find('\n', result.find("$1"))], 16)
|
| 242 | remappingBank0[0] = int(result[result.find("$2")+4 : result.find('\n', result.find("$2"))], 16)
|
| 243 | remappingBank4[0][1] = int(result[result.find("$3")+4 : result.find('\n', result.find("$3"))], 16)
|
| 244 | remappingBank4[0][0] = int(result[result.find("$4")+4 : result.find('\n', result.find("$4"))], 16)
|
| 245 | remappingBank4[1][1] = int(result[result.find("$5")+4 : result.find('\n', result.find("$5"))], 16)
|
| 246 | remappingBank4[1][0] = int(result[result.find("$6")+4 : result.find('\n', result.find("$6"))], 16)
|
| 247 | print("Bank0/1 \t\t MD address: 0x%08x <-> AP address 0x%08x"%(remappingBank0[0], remappingBank0[1]))
|
| 248 | print("Bank4(noncacheable) \t MD address: 0x%08x <-> AP address 0x%08x"%(remappingBank4[0][0], remappingBank4[0][1]))
|
| 249 | print("Bank4(cacheable) \t MD address: 0x%08x <-> AP address 0x%08x"%(remappingBank4[1][0], remappingBank4[1][1]))
|
| 250 |
|
| 251 | GetDRAMFileOffset(inputFileName)
|
| 252 |
|
| 253 | return
|
| 254 |
|
| 255 | def GetAPInfo(coreDumpFile) :
|
| 256 | checkInfoList = ["BRANCH_INFO=" , "VERNO=", "SUBTARGET=", "PLATFORM="]
|
| 257 | apLoadInfo = []
|
| 258 |
|
| 259 | inp = open(coreDumpFile, "rb")
|
| 260 | for info in checkInfoList :
|
| 261 | stage = 0
|
| 262 | tempInfo = ""
|
| 263 | wantInfo = ""
|
| 264 |
|
| 265 | ch = inp.read(1)
|
| 266 | while ch :
|
| 267 | if ord(ch) == ord(info[stage]) :
|
| 268 | stage += 1
|
| 269 | tempInfo = tempInfo + ch.decode()
|
| 270 | else :
|
| 271 | stage = 0
|
| 272 | tempInfo = ""
|
| 273 |
|
| 274 | if stage == len(info) :
|
| 275 | ch = inp.read(1)
|
| 276 | if (ord(ch) >= ord('A') and ord(ch) <= ord('Z')) or (ord(ch) >= ord('a') and ord(ch) <= ord('z')) :
|
| 277 | while ord(ch) != ord('\n') :
|
| 278 | wantInfo = wantInfo + ch.decode()
|
| 279 | ch = inp.read(1)
|
| 280 | apLoadInfo.append(wantInfo)
|
| 281 | break
|
| 282 | else :
|
| 283 | stage = 0
|
| 284 | tempInfo = ""
|
| 285 |
|
| 286 | ch = inp.read(1)
|
| 287 | if len(checkInfoList) != len(apLoadInfo):
|
| 288 | return []
|
| 289 | return apLoadInfo
|
| 290 |
|
| 291 |
|
| 292 | def AutoFindAPELF(coreDumpFile) :
|
| 293 | print ("======\nAuto find AP ELF mode...")
|
| 294 | apInfo = GetAPInfo(coreDumpFile)
|
| 295 | if len(apInfo) == 0 :
|
| 296 | print("\nCan't find AP version info in full RAM dump!\nPlease enter the vmliux path manually!")
|
| 297 | exit()
|
| 298 |
|
| 299 | print("\nBRANCH_INFO:\t%s\nVERNO:\t\t%s\nSUBTARGET:\t%s\nPLATFORM:\t%s\n" %(apInfo[0], apInfo[1], apInfo[2], apInfo[3]))
|
| 300 |
|
| 301 | vmlinuxPath = apSymbolPathLINUX + apInfo[0] + "/Symbols/" + apInfo[1] + "/" + apInfo[3] + "/" + apInfo[2] + "/vmlinux"
|
| 302 |
|
| 303 | if os.path.isfile(vmlinuxPath) == False :
|
| 304 | print("Can't find the vmlinux in %s !\nPlease update your AP version or enter the vmliux path manually!" %vmlinuxPath)
|
| 305 | exit()
|
| 306 |
|
| 307 | print("vmlinux path : " + vmlinuxPath + "\n")
|
| 308 |
|
| 309 | return vmlinuxPath
|
| 310 |
|
| 311 |
|
| 312 | # Manual input mode (for backup)
|
| 313 | def ManualInput() :
|
| 314 | bank0StartAddress = input("Please enter the AP address mapping to Bank0/1 (0x00000000) :\n")
|
| 315 | bank4MDCacheableStartAddress = input("Please enter the Bank4 cacheable MD address :\n")
|
| 316 | bank4CacheableStartAddress = input("Please enter the AP address mapping to Bank4 (cacheable) :\n")
|
| 317 | bank4UncacheableStartAddress = input("Please enter the AP address mapping to Bank4 (uncacheable) :\n")
|
| 318 |
|
| 319 | remappingBank0[1] = int(bank0StartAddress, 16)
|
| 320 | remappingBank4[1][0] = int(bank4MDCacheableStartAddress, 16)
|
| 321 | remappingBank4[1][1] = int(bank4CacheableStartAddress, 16)
|
| 322 | remappingBank4[0][1] = int(bank4UncacheableStartAddress, 16)
|
| 323 |
|
| 324 | def ParseMRDUMPBIHeader(coreDumpFile) :
|
| 325 | inp = open(coreDumpFile, "rb")
|
| 326 | stage = 0
|
| 327 | currentPos = 1
|
| 328 | foundMRDUMPBI = False
|
| 329 |
|
| 330 | GetDRAMFileOffset(coreDumpFile)
|
| 331 |
|
| 332 | ch = inp.read(1)
|
| 333 |
|
| 334 | # MRDUMPBI should be stored before DRAM dump
|
| 335 | while ch and currentPos <= fileOffset:
|
| 336 | # Parsing MRDUMPBI to find MD/AP remapping info
|
| 337 | if ord(ch) == ord(MRDUMPBI[stage]) :
|
| 338 | stage += 1
|
| 339 | else :
|
| 340 | stage = 0
|
| 341 |
|
| 342 | currentPos = currentPos + 1
|
| 343 |
|
| 344 | if stage == len(MRDUMPBI) :
|
| 345 | # Get AP/MD address remapping info
|
| 346 | remappingBank0[1] = int.from_bytes(inp.read(8), "little")
|
| 347 | remappingBank0[0] = int.from_bytes(inp.read(8), "little")
|
| 348 | remappingBank4[1][1] = int.from_bytes(inp.read(8), "little")
|
| 349 | remappingBank4[1][0] = int.from_bytes(inp.read(8), "little")
|
| 350 | remappingBank4[0][1] = int.from_bytes(inp.read(8), "little")
|
| 351 | remappingBank4[0][0] = int.from_bytes(inp.read(8), "little")
|
| 352 |
|
| 353 | print("Bank0/1 \t\t MD address: 0x%08x <-> AP address: 0x%08x"%(remappingBank0[0], remappingBank0[1]))
|
| 354 | print("Bank4(noncacheable) \t MD address: 0x%08x <-> AP address: 0x%08x"%(remappingBank4[0][0], remappingBank4[0][1]))
|
| 355 | print("Bank4(cacheable) \t MD address: 0x%08x <-> AP address: 0x%08x"%(remappingBank4[1][0], remappingBank4[1][1]))
|
| 356 |
|
| 357 | foundMRDUMPBI = True
|
| 358 |
|
| 359 | break
|
| 360 |
|
| 361 | ch = inp.read(1)
|
| 362 |
|
| 363 | if foundMRDUMPBI == False :
|
| 364 | print("\nCan't find MRDUMPBI! The AP version doesn't provide AP/MD address remapping info!!\n\nEnter maunal input mode: \n")
|
| 365 | ManualInput()
|
| 366 |
|
| 367 |
|
| 368 |
|
| 369 | if __name__ == "__main__":
|
| 370 | print("MIDR dump post-processing script V %s"%version)
|
| 371 |
|
| 372 | inputFileName, outputFileName, useMRDumptool, elf, dumpToolPath = ParsingArgument()
|
| 373 |
|
| 374 | if useMRDumptool == "True" :
|
| 375 | # Legacy version : need mrdump tool and vmlinux file to get AP/MD address remapping
|
| 376 | if os.name != "posix" :
|
| 377 | print("\nmrdump tool only can run on Linux!")
|
| 378 | exit()
|
| 379 |
|
| 380 | # Test mrdump tool
|
| 381 | proc = Popen("%s "%dumpToolPath, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
| 382 | result = proc.communicate()
|
| 383 | if str(result[1], 'utf-8') != "" :
|
| 384 | print(str(result[1], 'utf-8'))
|
| 385 | print("Please enter the correct mrdump tool path!")
|
| 386 | exit()
|
| 387 |
|
| 388 | if elf == '' :
|
| 389 | elf = AutoFindAPELF(inputFileName)
|
| 390 |
|
| 391 | print("======\nGet MD/AP address remapping information by mrdump tool...")
|
| 392 | MRDUMPToolParser(inputFileName, elf, dumpToolPath)
|
| 393 | print("\nDone!\n")
|
| 394 | else :
|
| 395 | # From V1.2 : AP write AP/MD address remapping info to SYS_COREDUMP header, we can parse header to get those info
|
| 396 | print("======\nGet MD/AP address remapping information from dump header...")
|
| 397 | ParseMRDUMPBIHeader(inputFileName)
|
| 398 | print("\nDone!\n")
|
| 399 |
|
| 400 | print("======\n\nGenerating FULL Memory Dump File...\n")
|
| 401 | RebuildFullMemoryDumpFile(inputFileName, outputFileName)
|
| 402 | print("Done!")
|