86 lines
3.4 KiB
Python
86 lines
3.4 KiB
Python
|
import os
|
||
|
import struct
|
||
|
import sys
|
||
|
|
||
|
"""
|
||
|
row-by-row dump
|
||
|
page = data + spare metadata + iokit return code + iokit return code 2
|
||
|
"""
|
||
|
class NANDImageFlat(object):
|
||
|
def __init__(self, filename, geometry):
|
||
|
flags = os.O_RDONLY
|
||
|
if sys.platform == "win32":
|
||
|
flags |= os.O_BINARY
|
||
|
self.fd = os.open(filename, flags)
|
||
|
self.nCEs = geometry["#ce"]
|
||
|
self.pageSize = geometry["#page-bytes"]
|
||
|
self.metaSize = geometry.get("meta-per-logical-page", 12)
|
||
|
self.dumpedPageSize = geometry.get("dumpedPageSize", self.pageSize + self.metaSize + 8)
|
||
|
self.hasIOKitStatus = True
|
||
|
if self.dumpedPageSize == self.pageSize + geometry["#spare-bytes"] or self.dumpedPageSize == self.pageSize + self.metaSize:
|
||
|
self.hasIOKitStatus = False
|
||
|
self.blankPage = "\xFF" * self.pageSize
|
||
|
self.blankSpare = "\xFF" * self.metaSize
|
||
|
self.imageSize = os.path.getsize(filename)
|
||
|
expectedSize = geometry["#ce"] * geometry["#ce-blocks"] * geometry["#block-pages"] * self.dumpedPageSize
|
||
|
if self.imageSize < expectedSize:
|
||
|
raise Exception("Error: image appears to be truncated, expected size=%d" % expectedSize)
|
||
|
print "Image size matches expected size, looks ok"
|
||
|
|
||
|
def _readPage(self, ce, page):
|
||
|
i = page * self.nCEs + ce
|
||
|
off = i * self.dumpedPageSize
|
||
|
os.lseek(self.fd, off, os.SEEK_SET)
|
||
|
return os.read(self.fd, self.dumpedPageSize)
|
||
|
|
||
|
def readPage(self, ce, page):
|
||
|
d = self._readPage(ce, page)
|
||
|
if not d or len(d) != self.dumpedPageSize:
|
||
|
return None,None
|
||
|
if self.hasIOKitStatus:
|
||
|
r1,r2 = struct.unpack("<LL", d[self.pageSize+self.metaSize:self.pageSize+self.metaSize+8])
|
||
|
if r1 != 0x0:
|
||
|
return None, None
|
||
|
data = d[:self.pageSize]
|
||
|
spare = d[self.pageSize:self.pageSize+self.metaSize]
|
||
|
if not self.hasIOKitStatus and data == self.blankPage and spare == self.blankSpare:
|
||
|
return None,None
|
||
|
return spare, data
|
||
|
|
||
|
"""
|
||
|
iEmu NAND format
|
||
|
one file for each CE, start with chip id (8 bytes) then pages
|
||
|
page = non-empty flag (1 byte) + data + spare metadata (12 bytes)
|
||
|
"""
|
||
|
class NANDImageSplitCEs(object):
|
||
|
def __init__(self, folder, geometry):
|
||
|
flags = os.O_RDONLY
|
||
|
if sys.platform == "win32":
|
||
|
flags |= os.O_BINARY
|
||
|
self.fds = []
|
||
|
self.nCEs = geometry["#ce"]
|
||
|
self.pageSize = geometry["#page-bytes"]
|
||
|
self.metaSize = 12
|
||
|
self.npages = 0
|
||
|
self.dumpedPageSize = 1 + self.pageSize + self.metaSize
|
||
|
for i in xrange(self.nCEs):
|
||
|
fd = os.open(folder + "/ce_%d.bin" % i, flags)
|
||
|
self.fds.append(fd)
|
||
|
self.npages += os.fstat(fd).st_size / self.dumpedPageSize
|
||
|
|
||
|
def _readPage(self, ce, page):
|
||
|
fd = self.fds[ce]
|
||
|
off = 8 + page * self.dumpedPageSize #skip chip id
|
||
|
os.lseek(fd, off, os.SEEK_SET)
|
||
|
return os.read(fd, self.dumpedPageSize)
|
||
|
|
||
|
def readPage(self, ce, page):
|
||
|
d = self._readPage(ce, page)
|
||
|
if not d or len(d) != self.dumpedPageSize:
|
||
|
return None,None
|
||
|
if d[0] != '1' and d[0] != '\x01':
|
||
|
return None,None
|
||
|
data = d[1:1+self.pageSize]
|
||
|
spare = d[1+self.pageSize:1+self.pageSize+self.metaSize]
|
||
|
return spare, data
|
||
|
|