Implemented stone-unpack mode

This commit is contained in:
Luxferre
2021-12-31 00:51:42 +02:00
parent eb034239db
commit a3f4e558d3
4 changed files with 537 additions and 124 deletions
+134 -122
View File
@@ -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)