initial code for dumping imessages in a reasonable format
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
from carver import NANDCarver
|
||||
from construct.core import Struct
|
||||
from construct.macros import ULInt32, ULInt16, Array, ULInt8, Padding
|
||||
from pprint import pprint
|
||||
from structs import SpareData
|
||||
from util import hexdump
|
||||
from vfl import VFL
|
||||
import plistlib
|
||||
|
||||
"""
|
||||
openiboot/plat-s5l8900/ftl.c
|
||||
openiboot/plat-s5l8900/includes/s5l8900/ftl.h
|
||||
"""
|
||||
FTLCxtLog = Struct("FTLCxtLog",
|
||||
ULInt32("usn"),
|
||||
ULInt16("wVbn"),
|
||||
ULInt16("wLbn"),
|
||||
ULInt32("wPageOffsets"),
|
||||
ULInt16("pagesUsed"),
|
||||
ULInt16("pagesCurrent"),
|
||||
ULInt32("isSequential")
|
||||
)
|
||||
|
||||
FTLCxtElement2 = Struct("FTLCxtElement2",
|
||||
ULInt16("field_0"),
|
||||
ULInt16("field_2")
|
||||
)
|
||||
|
||||
FTLCxt = Struct("FTLCxt",
|
||||
ULInt32("usnDec"),
|
||||
ULInt32("nextblockusn"),
|
||||
ULInt16("wNumOfFreeVb"),
|
||||
ULInt16("nextFreeIdx"),
|
||||
ULInt16("swapCounter"),
|
||||
Array(20, ULInt16("awFreeVb")),
|
||||
ULInt16("field_36"),
|
||||
Array(18, ULInt32("pages_for_pawMapTable")),
|
||||
Array(36, ULInt32("pages_for_pawEraseCounterTable")),
|
||||
Array(34, ULInt32("pages_for_wPageOffsets")),
|
||||
ULInt32("pawMapTable"),
|
||||
ULInt32("pawEraseCounterTable"),
|
||||
ULInt32("wPageOffsets"),
|
||||
Array(18, FTLCxtLog),
|
||||
ULInt32("eraseCounterPagesDirty"),
|
||||
ULInt16("unk3"),
|
||||
Array(3, ULInt16("FTLCtrlBlock")),
|
||||
ULInt32("FTLCtrlPage"),
|
||||
ULInt32("clean"),
|
||||
Array(36, ULInt32("pages_for_pawReadCounterTable")),
|
||||
ULInt32("pawReadCounterTable"),
|
||||
Array(5, FTLCxtElement2),
|
||||
ULInt32("field_3C8"),
|
||||
ULInt32("totalReadCount"),
|
||||
ULInt32("page_for_FTLCountsTable"),
|
||||
ULInt32("hasFTLCountsTable"),
|
||||
Padding(0x420), #, ULInt8("field_3D8")),
|
||||
ULInt32("versionLower"),
|
||||
ULInt32("versionUpper")
|
||||
)
|
||||
|
||||
FTL_CTX_TYPE = 0x43
|
||||
FTL_BLOCK_MAP = 0x44
|
||||
FTL_ERASE_COUNTER = 0x46
|
||||
FTL_MOUNTED = 0x47
|
||||
FTL_CTX_TYPE_MAX = 0x4F
|
||||
USER_TYPE = 0x40
|
||||
USER_LAST_TYPE = 0x41 #last user page in superblock?
|
||||
|
||||
class FTL(object):
|
||||
def __init__(self, nand, vfl):
|
||||
self.nand = nand
|
||||
self.vfl = vfl
|
||||
self.pawMapTable = {} #maps logical blocks to virtual blocks
|
||||
self.pLogs = {}
|
||||
if not self.FTL_open():
|
||||
self.FTL_restore()
|
||||
|
||||
def FTL_open(self):
|
||||
minUsnDec = 0xffffffff
|
||||
ftlCtrlBlock = 0xffff
|
||||
for vb in self.vfl.VFL_get_FTLCtrlBlock():
|
||||
s, d = self.vfl.read_single_page(vb * self.vfl.pages_per_sublk)
|
||||
if not s:
|
||||
continue
|
||||
if s.type >= FTL_CTX_TYPE and s.type <= FTL_CTX_TYPE_MAX:
|
||||
if s.usn < minUsnDec:
|
||||
ftlCtrlBlock = vb
|
||||
minUsnDec = s.usn
|
||||
|
||||
print ftlCtrlBlock
|
||||
self.ftlCtrlBlock = ftlCtrlBlock
|
||||
for p in xrange(self.vfl.pages_per_sublk-1,1, -1):
|
||||
s, d = self.vfl.read_single_page(ftlCtrlBlock * self.vfl.pages_per_sublk + p)
|
||||
if not s:
|
||||
continue
|
||||
#print s
|
||||
#print p
|
||||
if s.type == FTL_CTX_TYPE:
|
||||
print s.usn
|
||||
ctx = FTLCxt.parse(d)
|
||||
if ctx.versionLower == 0x46560001:
|
||||
print ctx
|
||||
assert ctx.FTLCtrlPage == (ftlCtrlBlock * self.vfl.pages_per_sublk + p)
|
||||
break
|
||||
else:
|
||||
print "Unclean shutdown, last type 0x%x" % s.type
|
||||
return False
|
||||
self.ctx = ctx
|
||||
print "FTL_open OK !"
|
||||
return True
|
||||
|
||||
def determine_block_type(self, block):
|
||||
maxUSN = 0
|
||||
isSequential = True
|
||||
for page in xrange(self.vfl.pages_per_sublk-1,1, -1):
|
||||
s, _ = self.vfl.read_single_page(block * self.vfl.pages_per_sublk + page)
|
||||
if not s:
|
||||
continue
|
||||
if s.usn > maxUSN:
|
||||
maxUSN = s.usn
|
||||
if s.lpn % self.vfl.pages_per_sublk != page:
|
||||
isSequential = False
|
||||
return isSequential, maxUSN
|
||||
return isSequential, maxUSN
|
||||
|
||||
def FTL_restore(self):
|
||||
self.pLogs = self.vfl.nand.loadCachedData("pLogs")
|
||||
self.pawMapTable = self.vfl.nand.loadCachedData("pawMapTable")
|
||||
if self.pLogs and self.pawMapTable:
|
||||
print "Found cached FTL restore information"
|
||||
return
|
||||
self.pawMapTable = {}
|
||||
self.pLogs = {}
|
||||
ctx = None
|
||||
for p in xrange(self.vfl.pages_per_sublk-1,1, -1):
|
||||
s, d = self.vfl.read_single_page(self.ftlCtrlBlock * self.vfl.pages_per_sublk + p)
|
||||
if not s:
|
||||
continue
|
||||
if s.type == FTL_CTX_TYPE:
|
||||
print s.usn
|
||||
ctx = FTLCxt.parse(d)
|
||||
if ctx.versionLower == 0x46560001:
|
||||
print ctx
|
||||
assert ctx.FTLCtrlPage == (self.ftlCtrlBlock * self.vfl.pages_per_sublk + p)
|
||||
print "Found most recent ctx"
|
||||
break
|
||||
if not ctx:
|
||||
print "FTL_restore fail did not find ctx"
|
||||
raise
|
||||
blockMap = {}
|
||||
self.nonSequential = {}
|
||||
print "FTL_restore in progress ..."
|
||||
for sblock in xrange(self.vfl.userSuBlksTotal + 23):
|
||||
for page in xrange(self.vfl.pages_per_sublk):
|
||||
s, d = self.vfl.read_single_page(sblock * self.vfl.pages_per_sublk + page)
|
||||
if not s:
|
||||
continue
|
||||
if s.type >= FTL_CTX_TYPE and s.type <= FTL_CTX_TYPE_MAX:
|
||||
break
|
||||
if s.type != USER_TYPE and s.type != USER_LAST_TYPE:
|
||||
print "Weird page type %x at %x %x" % (s.type, sblock, page)
|
||||
continue
|
||||
if s.lpn % self.vfl.pages_per_sublk != page:
|
||||
print "Block %d non sequential" % sblock
|
||||
self.nonSequential[sblock] = 1
|
||||
blockMap[sblock] = (s.lpn / self.vfl.pages_per_sublk, s.usn)
|
||||
break
|
||||
|
||||
z = dict([(i, [(a, blockMap[a][1]) for a in blockMap.keys() if blockMap[a][0] ==i]) for i in xrange(self.vfl.userSuBlksTotal)])
|
||||
for k,v in z.items():
|
||||
if len(v) == 2:
|
||||
print k, v
|
||||
vbA, usnA = v[0]
|
||||
vbB, usnB = v[1]
|
||||
if usnA > usnB: #smallest USN is map block, highest log block
|
||||
self.pawMapTable[k] = vbB
|
||||
self.restoreLogBlock(k, vbA)
|
||||
else:
|
||||
self.pawMapTable[k] = vbA
|
||||
self.restoreLogBlock(k, vbB)
|
||||
elif len(v) > 2:
|
||||
raise Exception("fufu", k, v)
|
||||
else:
|
||||
self.pawMapTable[k] = v[0][0]
|
||||
self.vfl.nand.cacheData("pLogs", self.pLogs)
|
||||
self.vfl.nand.cacheData("pawMapTable", self.pawMapTable)
|
||||
|
||||
def restoreLogBlock(self, lbn, vbn):
|
||||
log = {"wVbn": vbn, "wPageOffsets": {}}
|
||||
for page in xrange(self.vfl.pages_per_sublk):
|
||||
s, d = self.vfl.read_single_page(vbn * self.vfl.pages_per_sublk + page)
|
||||
if not s:
|
||||
break
|
||||
log["wPageOffsets"][s.lpn % self.vfl.pages_per_sublk] = page
|
||||
self.pLogs[lbn] = log
|
||||
|
||||
def mapPage(self, lbn, offset):
|
||||
if self.pLogs.has_key(lbn):
|
||||
if self.pLogs[lbn]["wPageOffsets"].has_key(offset):
|
||||
offset = self.pLogs[lbn]["wPageOffsets"][offset]
|
||||
#print "mapPage got log %d %d" % (lbn, offset)
|
||||
return self.pLogs[lbn]["wVbn"] * self.vfl.pages_per_sublk + offset
|
||||
if not self.pawMapTable.has_key(lbn):
|
||||
return 0xFFFFFFFF
|
||||
return self.pawMapTable[lbn] * self.vfl.pages_per_sublk + offset
|
||||
|
||||
def readLPN(self, lpn, key=None):
|
||||
lbn = lpn / self.vfl.pages_per_sublk
|
||||
offset = lpn % self.vfl.pages_per_sublk
|
||||
vpn = self.mapPage(lbn, offset)
|
||||
if vpn == 0xFFFFFFFF:
|
||||
print "lbn not found %d" % lbn
|
||||
return "\xFF" * self.nand.pageSize
|
||||
s,d = self.vfl.read_single_page(vpn, key, lpn)
|
||||
if not s:
|
||||
return None
|
||||
if s.lpn != lpn:
|
||||
raise Exception("FTL translation FAIL spare lpn=%d vs expected %d" % (s.lpn, lpn))
|
||||
return d
|
||||
|
||||
Reference in New Issue
Block a user