Implemented stone-unpack mode
This commit is contained in:
+134
-122
@@ -4,6 +4,7 @@ import usb
|
||||
import sys, time
|
||||
import os
|
||||
import unicmd
|
||||
import stoned
|
||||
|
||||
# global params
|
||||
|
||||
@@ -162,12 +163,13 @@ if __name__ == '__main__': # main app start
|
||||
from argparse import ArgumentParser
|
||||
rootdir = os.path.dirname(os.path.realpath(__file__))
|
||||
parser = ArgumentParser(description='UniFlash: an opensource Unisoc/Spreadtrum feature phone flash reader/writer', epilog='(c) Luxferre 2021 --- No rights reserved <https://unlicense.org>')
|
||||
parser.add_argument('mode', help='Operation mode (flash/dump)')
|
||||
parser.add_argument('file', help='File to read the flash data from or write the dump into')
|
||||
parser.add_argument('mode', help='Operation mode (flash/dump/stone-unpack)')
|
||||
parser.add_argument('file', help='File to read the flash data from or write the dump into, or the stone file to unpack')
|
||||
parser.add_argument('-p','--partid', type=auto_int, default=0x80000003, help='partition ID for readback (defaults to 0x80000003 that can address full flash space on SC6531E/F/M)')
|
||||
parser.add_argument('-s','--start', type=auto_int, default=0, help='start position (in the partition, defaults to 0)')
|
||||
parser.add_argument('-l', '--length', type=auto_int, default=0x400000, help='data length in bytes to read/write, defaults to 0x400000')
|
||||
parser.add_argument('-t','--target', default='sc6531efm_generic', help='Preinstalled target (defaults to sc6531efm_generic, overridable with individual FDL parameters)')
|
||||
parser.add_argument('-d','--directory', default=None, help='Directory where component files will be written to in stone-unpack mode (defaults to the same where the main stone file resides)')
|
||||
parser.add_argument('-nr','--flash-noremap', action='store_true', help='Disable base address remapping for flashing')
|
||||
parser.add_argument('-e','--force-erase', action='store_true', help='Erase target flash memory area before flashing')
|
||||
parser.add_argument('-wf','--enable-write-flash', action='store_true', help='Send the write flash enable command before flashing (if necessary and supported)')
|
||||
@@ -183,137 +185,147 @@ if __name__ == '__main__': # main app start
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
is_flash = False
|
||||
if args.mode == 'flash':
|
||||
is_flash = True
|
||||
if args.mode.startswith('stone'): # stone-unpack mode
|
||||
imgfile = args.file
|
||||
imgdir = os.path.dirname(os.path.realpath(imgfile))
|
||||
if args.directory is not None:
|
||||
imgdir = os.path.realpath(args.directory)
|
||||
|
||||
# parse target and resolve the parameters from it first
|
||||
paramdelim = '_'
|
||||
target = args.target + paramdelim
|
||||
fdlDir = rootdir + '/fdls'
|
||||
fdlList = []
|
||||
for root, dirs, files in os.walk(fdlDir):
|
||||
for name in files:
|
||||
if name.startswith(target):
|
||||
paramstr = os.path.splitext(name)[0].split(target)[1]
|
||||
params = paramstr.split(paramdelim)
|
||||
fdlList.append((params[1], params[0], fdlDir+'/'+name))
|
||||
# resulting fdl list: (tag, address, path)
|
||||
fdlSingleName = None
|
||||
fdlSingleAddr = None
|
||||
for tag, addr, path in fdlList:
|
||||
if tag == 'single':
|
||||
fdlSingleName = path
|
||||
fdlSingleAddr = auto_int(addr)
|
||||
elif tag == 'fdl1':
|
||||
fdl1Name = path
|
||||
fdl1Addr = auto_int(addr)
|
||||
elif tag == 'fdl2':
|
||||
fdl2Name = path
|
||||
fdl2Addr = auto_int(addr)
|
||||
print('Unpacking %s to %s' % (imgfile, imgdir))
|
||||
stoned.unpack_stone(imgfile, imgdir)
|
||||
|
||||
# override target with the individual parameters if necessary
|
||||
UNISOC_VID = args.device_vid
|
||||
UNISOC_PID = args.device_pid
|
||||
if args.fdl1_addr is not None:
|
||||
fdl1Addr = args.fdl1_addr
|
||||
if args.fdl2_addr is not None:
|
||||
fdl2Addr = args.fdl2_addr
|
||||
if args.fdl1_file is not None:
|
||||
fdl1Name = args.fdl1_file
|
||||
if args.fdl2_file is not None:
|
||||
fdl2Name = args.fdl2_file
|
||||
if args.single_fdl_file is not None:
|
||||
fdlSingleName = args.single_fdl_file
|
||||
if args.single_fdl_addr is not None:
|
||||
fdlSingleAddr = args.single_fdl_addr
|
||||
outfile = args.file
|
||||
partitionId = args.partid
|
||||
readbs = args.block_size
|
||||
readoffset = args.start
|
||||
readlen = args.length
|
||||
forceErase = args.force_erase
|
||||
sendEnableWriteFlash = args.enable_write_flash
|
||||
singleFdlMode = False
|
||||
fdl1Label = 'FDL1'
|
||||
fdl2Label = 'FDL2'
|
||||
else: # flash/dump mode
|
||||
is_flash = False
|
||||
if args.mode == 'flash':
|
||||
is_flash = True
|
||||
|
||||
# override flash base addr based on the target
|
||||
# parse target and resolve the parameters from it first
|
||||
paramdelim = '_'
|
||||
target = args.target + paramdelim
|
||||
fdlDir = rootdir + '/fdls'
|
||||
fdlList = []
|
||||
for root, dirs, files in os.walk(fdlDir):
|
||||
for name in files:
|
||||
if name.startswith(target):
|
||||
paramstr = os.path.splitext(name)[0].split(target)[1]
|
||||
params = paramstr.split(paramdelim)
|
||||
fdlList.append((params[1], params[0], fdlDir+'/'+name))
|
||||
# resulting fdl list: (tag, address, path)
|
||||
fdlSingleName = None
|
||||
fdlSingleAddr = None
|
||||
for tag, addr, path in fdlList:
|
||||
if tag == 'single':
|
||||
fdlSingleName = path
|
||||
fdlSingleAddr = auto_int(addr)
|
||||
elif tag == 'fdl1':
|
||||
fdl1Name = path
|
||||
fdl1Addr = auto_int(addr)
|
||||
elif tag == 'fdl2':
|
||||
fdl2Name = path
|
||||
fdl2Addr = auto_int(addr)
|
||||
|
||||
if target.startswith('sc6530'):
|
||||
UNISOC_FLASH_BASE_ADDR = UNISOC_FLASH_BASE_ADDR_OLD
|
||||
# override target with the individual parameters if necessary
|
||||
UNISOC_VID = args.device_vid
|
||||
UNISOC_PID = args.device_pid
|
||||
if args.fdl1_addr is not None:
|
||||
fdl1Addr = args.fdl1_addr
|
||||
if args.fdl2_addr is not None:
|
||||
fdl2Addr = args.fdl2_addr
|
||||
if args.fdl1_file is not None:
|
||||
fdl1Name = args.fdl1_file
|
||||
if args.fdl2_file is not None:
|
||||
fdl2Name = args.fdl2_file
|
||||
if args.single_fdl_file is not None:
|
||||
fdlSingleName = args.single_fdl_file
|
||||
if args.single_fdl_addr is not None:
|
||||
fdlSingleAddr = args.single_fdl_addr
|
||||
outfile = args.file
|
||||
partitionId = args.partid
|
||||
readbs = args.block_size
|
||||
readoffset = args.start
|
||||
readlen = args.length
|
||||
forceErase = args.force_erase
|
||||
sendEnableWriteFlash = args.enable_write_flash
|
||||
singleFdlMode = False
|
||||
fdl1Label = 'FDL1'
|
||||
fdl2Label = 'FDL2'
|
||||
|
||||
if args.flash_noremap == True:
|
||||
print('Flash remapping disabled')
|
||||
UNISOC_FLASH_BASE_ADDR = 0
|
||||
# override flash base addr based on the target
|
||||
|
||||
if fdlSingleName is not None:
|
||||
singleFdlMode = True
|
||||
fdl1Addr = fdlSingleAddr
|
||||
fdl1Name = fdlSingleName
|
||||
fdl1Label = 'FDL'
|
||||
fdl2Label = 'FDL'
|
||||
print('Using a single FDL %s, loading to 0x%X' % (fdlSingleName, fdlSingleAddr))
|
||||
else:
|
||||
print('Using FDL1 %s, loading to 0x%X' % (fdl1Name, fdl1Addr))
|
||||
print('Using FDL2 %s, loading to 0x%X' % (fdl2Name, fdl2Addr))
|
||||
if target.startswith('sc6530'):
|
||||
UNISOC_FLASH_BASE_ADDR = UNISOC_FLASH_BASE_ADDR_OLD
|
||||
|
||||
# initial connection
|
||||
print('Connect the device %X:%X while holding the bootkey...' % (UNISOC_VID, UNISOC_PID) )
|
||||
dev, epIn, epOut = connect(UNISOC_VID, UNISOC_PID)
|
||||
handshake()
|
||||
if args.flash_noremap == True:
|
||||
print('Flash remapping disabled')
|
||||
UNISOC_FLASH_BASE_ADDR = 0
|
||||
|
||||
def reconnect():
|
||||
global dev
|
||||
if dev is not None:
|
||||
usb.util.dispose_resources(dev)
|
||||
time.sleep(0.5)
|
||||
dev, epIn, epOut = connect(UNISOC_VID, UNISOC_PID)
|
||||
|
||||
print('Boot mode entered')
|
||||
|
||||
print('Sending ' + fdl1Label)
|
||||
send_file_to_addr(fdl1Name, fdl1Addr)
|
||||
print('Starting ' + fdl1Label)
|
||||
resp = reqresp(unicmd.cmd_data_exec(fdl1Addr))
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, False)
|
||||
if rcode == unicmd.BSL_REP_ACK:
|
||||
print(fdl1Label + ' started successfully, reconnecting...')
|
||||
reconnect()
|
||||
handshake(True)
|
||||
|
||||
if singleFdlMode:
|
||||
rcode = unicmd.BSL_REP_ACK
|
||||
if fdlSingleName is not None:
|
||||
singleFdlMode = True
|
||||
fdl1Addr = fdlSingleAddr
|
||||
fdl1Name = fdlSingleName
|
||||
fdl1Label = 'FDL'
|
||||
fdl2Label = 'FDL'
|
||||
print('Using a single FDL %s, loading to 0x%X' % (fdlSingleName, fdlSingleAddr))
|
||||
else:
|
||||
print('Protocol set up, sending FDL2')
|
||||
send_file_to_addr(fdl2Name, fdl2Addr, True)
|
||||
print('Starting FDL2')
|
||||
resp = reqresp(unicmd.cmd_data_exec(fdl2Addr), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
print('Using FDL1 %s, loading to 0x%X' % (fdl1Name, fdl1Addr))
|
||||
print('Using FDL2 %s, loading to 0x%X' % (fdl2Name, fdl2Addr))
|
||||
|
||||
# initial connection
|
||||
print('Connect the device %X:%X while holding the bootkey...' % (UNISOC_VID, UNISOC_PID) )
|
||||
dev, epIn, epOut = connect(UNISOC_VID, UNISOC_PID)
|
||||
handshake()
|
||||
|
||||
def reconnect():
|
||||
global dev
|
||||
if dev is not None:
|
||||
usb.util.dispose_resources(dev)
|
||||
time.sleep(0.5)
|
||||
dev, epIn, epOut = connect(UNISOC_VID, UNISOC_PID)
|
||||
|
||||
print('Boot mode entered')
|
||||
|
||||
print('Sending ' + fdl1Label)
|
||||
send_file_to_addr(fdl1Name, fdl1Addr)
|
||||
print('Starting ' + fdl1Label)
|
||||
resp = reqresp(unicmd.cmd_data_exec(fdl1Addr))
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, False)
|
||||
if rcode == unicmd.BSL_REP_ACK:
|
||||
print(fdl2Label + ' started successfully!')
|
||||
print(fdl1Label + ' started successfully, reconnecting...')
|
||||
reconnect()
|
||||
handshake(True)
|
||||
|
||||
resp = reqresp(unicmd.cmd_sync_full(), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not set the baudrate, response code is %X' % rcode
|
||||
|
||||
print(fdl2Label + ' running, may start interacting with flash memory')
|
||||
|
||||
if is_flash:
|
||||
|
||||
if sendEnableWriteFlash:
|
||||
resp = reqresp(unicmd.cmd_enable_write_flash(), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not send the flash write request, response code is %X' % rcode
|
||||
|
||||
print('Writing flash at offset 0x%X from %s...' % (readoffset, outfile))
|
||||
write_flash_mem(outfile, readoffset, readbs, forceErase)
|
||||
print('Flash memory written, disconnect the device!')
|
||||
if singleFdlMode:
|
||||
rcode = unicmd.BSL_REP_ACK
|
||||
else:
|
||||
read_partition(partitionId, readlen, readoffset, outfile, readbs)
|
||||
resp = reqresp(unicmd.cmd_reset(), True)
|
||||
print('Protocol set up, sending FDL2')
|
||||
send_file_to_addr(fdl2Name, fdl2Addr, True)
|
||||
print('Starting FDL2')
|
||||
resp = reqresp(unicmd.cmd_data_exec(fdl2Addr), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not reset the device, response code is %X' % rcode
|
||||
if rcode == unicmd.BSL_REP_ACK:
|
||||
print(fdl2Label + ' started successfully!')
|
||||
|
||||
if dev is not None:
|
||||
usb.util.dispose_resources(dev)
|
||||
resp = reqresp(unicmd.cmd_sync_full(), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not set the baudrate, response code is %X' % rcode
|
||||
|
||||
print(fdl2Label + ' running, may start interacting with flash memory')
|
||||
|
||||
if is_flash:
|
||||
|
||||
if sendEnableWriteFlash:
|
||||
resp = reqresp(unicmd.cmd_enable_write_flash(), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not send the flash write request, response code is %X' % rcode
|
||||
|
||||
print('Writing flash at offset 0x%X from %s...' % (readoffset, outfile))
|
||||
write_flash_mem(outfile, readoffset, readbs, forceErase)
|
||||
print('Flash memory written, disconnect the device!')
|
||||
else:
|
||||
read_partition(partitionId, readlen, readoffset, outfile, readbs)
|
||||
resp = reqresp(unicmd.cmd_reset(), True)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, True)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not reset the device, response code is %X' % rcode
|
||||
|
||||
if dev is not None:
|
||||
usb.util.dispose_resources(dev)
|
||||
|
||||
Reference in New Issue
Block a user