Implemented SC6531C readback and target system
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# UniFlash: an opensource Unisoc/Spreadtrum phone flash reader/writer
|
||||
# UniFlash: an opensource Unisoc/Spreadtrum feature phone flash reader/writer
|
||||
|
||||
## About
|
||||
|
||||
@@ -24,23 +24,43 @@ Run `python uniflash.py -h` to see all parameters. But there are several typical
|
||||
|
||||
**Note**: you need to hold a bootkey pressed when connecting the device for it to be detected correctly. This key can vary across devices. Typically it's Call, Soft Left, Soft Right, Center, 9 or #, but it can be anything else.
|
||||
|
||||
Some chipset versions (esp. the ones before SC6531E) require the following procedure to connect in order to initiate successful data transfer:
|
||||
|
||||
1. Pull out the battery and the cable.
|
||||
2. Insert the cable.
|
||||
3. Hold the bootkey and then insert the battery.
|
||||
|
||||
UniFlash ships with several typical targets that you can specify with `-t` (`--target`) parameter and not have to configure anything else:
|
||||
|
||||
- `sc6531efm_generic` (default) - for SC6531E/F/M with no signed FDLs;
|
||||
- `sc6530_generic` - for SC6530 and SC6531B/C/DA with no signed FDLs;
|
||||
- `sc7703a_generic` - for SC7703A with no signed FDLs.
|
||||
|
||||
If you want to, the targets are fully overridable with individual parameters, see program help for all details.
|
||||
|
||||
### SC6531E
|
||||
|
||||
This is the default target for UniFlash, FDLs for it are shipped in the repo and you don't need to configure anything else unless your model requires signed FDLs.
|
||||
This is the default target for UniFlash, FDLs for it are shipped in the repo and you don't need to configure anything (even `-t` parameter) else unless your model requires signed FDLs.
|
||||
|
||||
For SC6531E, firmware is usually 4MB long, so you just need to run `python uniflash.py dump your-output-file.bin` to dump the firmware image and `python uniflash.py flash your-input-file.bin` to flash it.
|
||||
|
||||
### SC6531F/M
|
||||
|
||||
For SC6531F or SC6531M, **specifying the wrong dump length and attempts to write flash from the same dump can make the device unbootable!**
|
||||
For SC6531F or SC6531M, the target is still `sc6531efm_generic` unless your model uses signed FDLs. However, **specifying the wrong dump length and attempts to write flash from the same dump can make the device unbootable!**
|
||||
|
||||
Here, firmware can be larger, so you need to pass in the length. As with any integer parameter here, you can pass it in hexadecimal format as well.
|
||||
|
||||
E.g. for CAT B26 (bootkey is `#`) the dumping command is: `python uniflash.py -l 0x800000 dump b26.bin`
|
||||
|
||||
### SC6531C
|
||||
|
||||
SC6531C is a single-FDL variant. Here, if your model doesn't require signed FDLs, you need to specify `sc6530_generic` target and typically 8MB length, for instance, for Alcatel OT-2051D the boot key is Call key and the command to dump is: `python uniflash.py -t sc6530_generic -l 0x800000 dump ot2051d.bin`
|
||||
|
||||
**Note**: for SC6531C, only readback is supported as of now.
|
||||
|
||||
### SC6531D and lower
|
||||
|
||||
For now, SC6531DA and other single-FDL variants of SC6531 chipset are not supported.
|
||||
For now, SC6531DA and other variants of SC6531 chipset older than SC6531CA are not supported.
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -263,5 +263,8 @@ def cmd_erase_flash(targetAddr, targetLen):
|
||||
datahdr = pack('>LL', targetAddr, targetLen)
|
||||
return shape_data_packet(BSL_CMD_ERASE_FLASH, datahdr)
|
||||
|
||||
def cmd_enable_write_flash():
|
||||
return shape_cmd_packet(BSL_CMD_ENABLE_WRITE_FLASH)
|
||||
|
||||
def cmd_end_flash_process():
|
||||
return shape_cmd_packet(BSL_CMD_END_PROCESS)
|
||||
|
||||
+64
-16
@@ -82,6 +82,8 @@ def send_file_to_addr(fname, faddr, fdlBooted = False, flashMode = False, fbs =
|
||||
resp = reqresp(unicmd.cmd_data_start(faddr, flen, dataCrc), fdlBooted)
|
||||
rcode, rlen, r = unicmd.resp_decode(resp, fdlBooted)
|
||||
assert rcode == unicmd.BSL_REP_ACK, 'Could not start data transfer, response code is %X' % rcode
|
||||
if rcode == unicmd.BSL_REP_LOG:
|
||||
print(r)
|
||||
print('Starting data transfer...')
|
||||
while fdata:
|
||||
buf = fdata[:pSize]
|
||||
@@ -148,30 +150,33 @@ def write_flash_mem(infile, offset, blocksize, forceErase):
|
||||
erase_flash_mem(flen, startAddr)
|
||||
send_file_to_addr(fdata, startAddr, True, True, blocksize)
|
||||
|
||||
# main code start
|
||||
|
||||
def auto_int(x):
|
||||
return int(x,0)
|
||||
|
||||
# main code start
|
||||
|
||||
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 SC6531E/F/M phone flash reader/writer', epilog='(c) Luxferre 2021 --- No rights reserved <https://unlicense.org>')
|
||||
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('-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('-e','--force-erase', type=bool, default=False, help='Erase target flash memory area before writing')
|
||||
parser.add_argument('-t','--target', default='sc6531efm_generic', help='Preinstalled target (defaults to sc6531efm_generic, overridable with individual FDL parameters)')
|
||||
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)')
|
||||
parser.add_argument('-bs','--block-size', type=auto_int, default=4096, help='Readback/write block size (in bytes), defaults to 4096')
|
||||
parser.add_argument('-dv','--device-vid', type=auto_int, default=UNISOC_VID, help='Override device vendor ID')
|
||||
parser.add_argument('-dp','--device-pid', type=auto_int, default=UNISOC_PID, help='Override device product ID')
|
||||
parser.add_argument('-fdl1','--fdl1-file', default=rootdir+'/fdls/sc6531efm_generic_0x40004000_fdl1.bin', help='Path to FDL1, defaults to the generic SC6531E/F/M FDL1 shipped with UniFlash')
|
||||
parser.add_argument('-addr1','--fdl1-addr', type=auto_int, default=0x40004000, help='Address to load FDL1 into, defaults to 0x40004000')
|
||||
parser.add_argument('-fdl2','--fdl2-file', default=rootdir+'/fdls/sc6531efm_generic_0x14000000_fdl2.bin', help='Path to FDL2, defaults to the generic SC6531E/F/M FDL2 shipped with UniFlash')
|
||||
parser.add_argument('-addr2','--fdl2-addr', type=auto_int, default=0x14000000, help='Address to load FDL2 into, defaults to 0x14000000')
|
||||
parser.add_argument('-sfdl','--single-fdl-file', default=None, help='Path to a single FDL (for old Spreadtrum chipsets)')
|
||||
parser.add_argument('-saddr','--single-fdl-addr', type=auto_int, default=0x34000000, help='Address to load the single FDL into, defaults to 0x34000000')
|
||||
parser.add_argument('-fdl1','--fdl1-file', default=None, help='Path to FDL1, overrides the target')
|
||||
parser.add_argument('-addr1','--fdl1-addr', type=auto_int, default=None, help='Address to load FDL1 into, overrides the target')
|
||||
parser.add_argument('-fdl2','--fdl2-file', default=None, help='Path to FDL2, overrides the target')
|
||||
parser.add_argument('-addr2','--fdl2-addr', type=auto_int, default=None, help='Address to load FDL2 into, overrides the target')
|
||||
parser.add_argument('-sfdl','--single-fdl-file', default=None, help='Path to a single FDL (for old Spreadtrum chipsets), overrides the target')
|
||||
parser.add_argument('-saddr','--single-fdl-addr', type=auto_int, default=None, help='Address to load the single FDL into, overrides the target')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -179,24 +184,61 @@ if __name__ == '__main__': # main app start
|
||||
if args.mode == 'flash':
|
||||
is_flash = True
|
||||
|
||||
# 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)
|
||||
|
||||
# override target with the individual parameters if necessary
|
||||
UNISOC_VID = args.device_vid
|
||||
UNISOC_PID = args.device_pid
|
||||
fdl1Addr = args.fdl1_addr
|
||||
fdl2Addr = args.fdl2_addr
|
||||
fdl1Name = args.fdl1_file
|
||||
fdl2Name = args.fdl2_file
|
||||
fdlSingleName = args.single_fdl_file
|
||||
fdlSingleAddr = args.single_fdl_addr
|
||||
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
|
||||
|
||||
if fdlSingleName is not None:
|
||||
singleFdlMode = True
|
||||
fdl1Addr = fdlSingleAddr
|
||||
@@ -250,6 +292,12 @@ if __name__ == '__main__': # main app start
|
||||
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!')
|
||||
|
||||
Reference in New Issue
Block a user