ST-Link/V2 flash ROM writer
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
2012-06-20 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
ST-Link/V2 flash ROM writer.
|
||||
* tool/stlinkv2.py: New.
|
||||
* tool/asm-thumb/opt_bytes_write.S: New.
|
||||
* tool/asm-thumb/flash_write.S: New.
|
||||
|
||||
2012-06-19 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.20.
|
||||
|
||||
2
NEWS
2
NEWS
@@ -23,7 +23,7 @@ Keystring is now computed by SHA-256 (it was SHA1 before).
|
||||
|
||||
** Protection improvements (even when internal data is disclosed)
|
||||
Three improvements. (1) Even if PW1 and Reset-code is same, content
|
||||
of encripted DEK is different now. (2) DEK is now encrypted and
|
||||
of encrypted DEK is different now. (2) DEK is now encrypted and
|
||||
decrypted by keystring in ECB mode (it was just a kind of xor by
|
||||
single block CFB mode). (3) Key data plus checksum are encrypted in
|
||||
CFB mode with initial vector (it will be able to switch OCB mode
|
||||
|
||||
2
tool/asm-thumb/README
Normal file
2
tool/asm-thumb/README
Normal file
@@ -0,0 +1,2 @@
|
||||
These assembler program are source code of program fragments in
|
||||
stlinkv2.py.
|
||||
39
tool/asm-thumb/flash_write.S
Normal file
39
tool/asm-thumb/flash_write.S
Normal file
@@ -0,0 +1,39 @@
|
||||
/* ARM Thumb Assembler code */
|
||||
// arm-none-eabi-gcc -Wa,-amhls=flash_write.lst -c flash_write.S
|
||||
|
||||
#define FLASH_CR_PG 0x0001 // == FLASH_SR_BSY
|
||||
#define FLASH_CR_ERRORS 0x0014 // == PGERR | WRPRTERR
|
||||
#define FLASH_SR_BSY 0x0001
|
||||
|
||||
#define FLASH_SR_OFFSET 0x0c
|
||||
#define FLASH_CR_OFFSET 0x10
|
||||
|
||||
#define COUNT 0x1000
|
||||
|
||||
.cpu cortex-m3
|
||||
.thumb
|
||||
movw r2, #COUNT
|
||||
ldr r0, .SRC_ADDR
|
||||
ldr r1, .TARGET_ADDR
|
||||
ldr r4, .FLASH_BASE_ADDR
|
||||
mov r5, #FLASH_CR_PG
|
||||
mov r6, #FLASH_CR_ERRORS
|
||||
mov r7, #0
|
||||
str r5, [r4, #FLASH_CR_OFFSET]
|
||||
0: ldrh r3, [r0, r7]
|
||||
strh r3, [r1, r7]
|
||||
1: ldr r3, [r4, #FLASH_SR_OFFSET]
|
||||
tst r3, r5
|
||||
bne 1b
|
||||
tst r3, r6
|
||||
bne 2f
|
||||
add r7, r7, #0x02
|
||||
cmp r7, r2
|
||||
bne 0b
|
||||
2: mov r7, #0
|
||||
str r7, [r4, #FLASH_CR_OFFSET]
|
||||
bkpt #0x00
|
||||
.align 2
|
||||
.FLASH_BASE_ADDR: .word 0x40022000
|
||||
.SRC_ADDR: .word 0x20000038
|
||||
.TARGET_ADDR: .word 0x08000000
|
||||
29
tool/asm-thumb/opt_bytes_write.S
Normal file
29
tool/asm-thumb/opt_bytes_write.S
Normal file
@@ -0,0 +1,29 @@
|
||||
/* ARM Thumb Assembler code */
|
||||
// arm-none-eabi-gcc -Wa,-amhls=opt_bytes_write.lst -c opt_bytes_write.S
|
||||
|
||||
#define FLASH_CR_OPTPG 0x0010
|
||||
#define FLASH_SR_BSY 0x0001
|
||||
|
||||
#define FLASH_SR_OFFSET 0x0c
|
||||
#define FLASH_CR_OFFSET 0x10
|
||||
|
||||
#define OB_RDP_UNLOCK 0x00a5
|
||||
|
||||
.cpu cortex-m3
|
||||
.thumb
|
||||
movw r0, #OB_RDP_UNLOCK
|
||||
ldr r1, .TARGET_ADDR
|
||||
ldr r2, .FLASH_BASE_ADDR
|
||||
mov r3, #FLASH_CR_OPTPG
|
||||
mov r4, #FLASH_SR_BSY
|
||||
str r3, [r2, #FLASH_CR_OFFSET]
|
||||
strh r0, [r1]
|
||||
1: ldr r0, [r2, #FLASH_SR_OFFSET]
|
||||
tst r0, r4
|
||||
bne 1b
|
||||
mov r0, #0
|
||||
str r0, [r2, #FLASH_CR_OFFSET]
|
||||
bkpt #0x00
|
||||
.align 2
|
||||
.FLASH_BASE_ADDR: .word 0x40022000
|
||||
.TARGET_ADDR: .word 0x1FFFF800
|
||||
475
tool/stlinkv2.py
Executable file
475
tool/stlinkv2.py
Executable file
@@ -0,0 +1,475 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
"""
|
||||
stlinkv2.py - a tool to control ST-Link/V2
|
||||
|
||||
Copyright (C) 2012 Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from struct import *
|
||||
import sys, time
|
||||
|
||||
# INPUT: binary file
|
||||
|
||||
# Assumes only single ST-Link/V2 device is attached to computer.
|
||||
|
||||
import usb
|
||||
|
||||
GPIOA=0x40010800
|
||||
OPTION_BYTES_ADDR=0x1ffff800
|
||||
RDP_KEY=0x00a5 # Unlock readprotection
|
||||
FLASH_BASE_ADDR=0x40022000
|
||||
|
||||
FLASH_KEYR= FLASH_BASE_ADDR+0x04
|
||||
FLASH_OPTKEYR= FLASH_BASE_ADDR+0x08
|
||||
FLASH_SR= FLASH_BASE_ADDR+0x0c
|
||||
FLASH_CR= FLASH_BASE_ADDR+0x10
|
||||
FLASH_AR= FLASH_BASE_ADDR+0x14
|
||||
FLASH_OBR= FLASH_BASE_ADDR+0x1c
|
||||
|
||||
FLASH_KEY1=0x45670123
|
||||
FLASH_KEY2=0xcdef89ab
|
||||
|
||||
FLASH_SR_BSY= 0x0001
|
||||
FLASH_SR_PGERR= 0x0004
|
||||
FLASH_SR_WRPRTERR= 0x0010
|
||||
FLASH_SR_EOP= 0x0020
|
||||
|
||||
FLASH_CR_PG= 0x0001
|
||||
FLASH_CR_PER= 0x0002
|
||||
FLASH_CR_MER= 0x0004
|
||||
FLASH_CR_OPTPG= 0x0010
|
||||
FLASH_CR_OPTER= 0x0020
|
||||
FLASH_CR_STRT= 0x0040
|
||||
FLASH_CR_LOCK= 0x0080
|
||||
FLASH_CR_OPTWRE= 0x0200
|
||||
|
||||
|
||||
def uint32(v):
|
||||
return v[0] + (v[1]<<8) + (v[2]<<16) + (v[3]<<24)
|
||||
|
||||
## HERE comes: "movw r2,#SIZE" instruction
|
||||
prog_flash_write_body = "\x0A\x48" + "\x0B\x49" + \
|
||||
"\x08\x4C" + "\x01\x25" + "\x14\x26" + "\x00\x27" + "\x25\x61" + \
|
||||
"\xC3\x5B" + "\xCB\x53" + "\xE3\x68" + "\x2B\x42" + "\xFC\xD1" + \
|
||||
"\x33\x42" + "\x02\xD1" + "\x02\x37" + "\x97\x42" + "\xF5\xD1" + \
|
||||
"\x00\x27" + "\x27\x61" + "\x00\xBE" + "\x00\x20\x02\x40" + \
|
||||
"\x38\x00\x00\x20"
|
||||
# .SRC_ADDR: 0x20000038
|
||||
## HERE comes: target_addr in 4-byte
|
||||
# .TARGET_ADDR
|
||||
|
||||
def gen_prog_flash_write(addr,size):
|
||||
return pack("<BBBB", (0x40 | (size&0xf000)>>12), (0xf2 | (size&0x0800)>>9),
|
||||
(size & 0x00ff), (0x02 | ((size&0x0700) >> 4))) + \
|
||||
prog_flash_write_body + pack("<I", addr)
|
||||
|
||||
|
||||
## HERE comes: "movw r0,#VAL" instruction
|
||||
prog_option_bytes_write_body = "\x06\x49" + "\x05\x4A" + "\x10\x23" + \
|
||||
"\x01\x24" + "\x13\x61" + "\x08\x80" + "\xD0\x68" + "\x20\x42" + \
|
||||
"\xFC\xD1" + "\x00\x20" + "\x10\x61" + "\x00\xBE" + "\x00\x20\x02\x40"
|
||||
## HERE comes: target_addr in 4-byte
|
||||
# .TARGET_ADDR
|
||||
|
||||
def gen_prog_option_bytes_write(addr,val):
|
||||
return pack("<BBBB", (0x40 | (val&0xf000)>>12), (0xf2 | (val&0x0800)>>9),
|
||||
(val & 0x00ff), (0x00 | ((val&0x0700) >> 4))) + \
|
||||
prog_option_bytes_write_body + pack("<I", addr)
|
||||
|
||||
|
||||
SRAM_ADDRESS=0x20000000
|
||||
BLOCK_SIZE=16384 # Should be less than (20KiB - 0x0038)
|
||||
BLOCK_WRITE_TIMEOUT=80 # Increase this when you increase BLOCK_SIZE
|
||||
|
||||
# This class only supports Gnuk (for now)
|
||||
class stlinkv2(object):
|
||||
def __init__(self, dev):
|
||||
self.__bulkout = 2
|
||||
self.__bulkin = 0x81
|
||||
|
||||
self.__timeout = 1000 # 1 second
|
||||
conf = dev.configurations[0]
|
||||
intf_alt = conf.interfaces[0]
|
||||
intf = intf_alt[0]
|
||||
if intf.interfaceClass != 0xff: # Vendor specific
|
||||
raise ValueError, "Wrong interface class"
|
||||
self.__devhandle = dev.open()
|
||||
try:
|
||||
self.__devhandle.setConfiguration(conf)
|
||||
except:
|
||||
pass
|
||||
self.__devhandle.claimInterface(intf)
|
||||
self.__devhandle.setAltInterface(intf)
|
||||
|
||||
def execute_get(self, cmd, res_len):
|
||||
self.__devhandle.bulkWrite(self.__bulkout, cmd, self.__timeout)
|
||||
res = self.__devhandle.bulkRead(self.__bulkin, res_len, self.__timeout)
|
||||
return res
|
||||
|
||||
def execute_put(self, cmd, data=None):
|
||||
self.__devhandle.bulkWrite(self.__bulkout, cmd, self.__timeout)
|
||||
if (data):
|
||||
self.__devhandle.bulkWrite(self.__bulkout, data, self.__timeout)
|
||||
|
||||
def stl_mode(self):
|
||||
v = self.execute_get("\xf5\x00", 2)
|
||||
return (v[1] * 256 + v[0])
|
||||
|
||||
def exit_from_dfu(self):
|
||||
self.__devhandle.bulkWrite(self.__bulkout, "\xf3\x07", self.__timeout)
|
||||
time.sleep(1)
|
||||
|
||||
def enter_swd(self):
|
||||
self.__devhandle.bulkWrite(self.__bulkout, "\xf2\x20\xa3", self.__timeout)
|
||||
time.sleep(1)
|
||||
|
||||
def get_status(self):
|
||||
v = self.execute_get("\xf2\x01\x00", 2)
|
||||
return (v[1] << 8) + v[0]
|
||||
# RUN:128, HALT:129
|
||||
|
||||
def enter_debug(self):
|
||||
v = self.execute_get("\xf2\x02\x00", 2)
|
||||
return (v[1] << 8) + v[0]
|
||||
|
||||
def exit_debug(self):
|
||||
self.execute_put("\xf2\x21\x00")
|
||||
|
||||
def reset_sys(self):
|
||||
v = self.execute_get("\xf2\x03\x00", 2)
|
||||
return (v[1] << 8) + v[0]
|
||||
|
||||
def read_memory(self, addr, length):
|
||||
return self.execute_get("\xf2\x07" + pack('<IH', addr, length), length)
|
||||
|
||||
def read_memory_u32(self, addr):
|
||||
return uint32(self.execute_get("\xf2\x07" + pack('<IH', addr, 4), 4))
|
||||
|
||||
def write_memory(self, addr, data):
|
||||
return self.execute_put("\xf2\x08" + pack('<IH', addr, len(data)), data)
|
||||
|
||||
def write_memory_u32(self, addr, data):
|
||||
return self.execute_put("\xf2\x08" + pack('<IH', addr, 4),
|
||||
pack('<I', data))
|
||||
|
||||
def read_reg(self, regno):
|
||||
return uint32(self.execute_get("\xf2\x05" + pack('<B', regno), 4))
|
||||
|
||||
def write_reg(self, regno, value):
|
||||
return self.execute_get("\xf2\x06" + pack('<BI', regno, value), 2)
|
||||
|
||||
def run(self):
|
||||
v = self.execute_get("\xf2\x09\x00", 2)
|
||||
return (v[1] << 8) + v[0]
|
||||
|
||||
def core_id(self):
|
||||
v = self.execute_get("\xf2\x22\x00", 4)
|
||||
return v[0] + (v[1]<<8) + (v[2]<<16) + (v[3]<<24)
|
||||
|
||||
# For FST-01-00
|
||||
def setup_led(self):
|
||||
apb2enr = self.read_memory_u32(0x40021018)
|
||||
apb2enr = apb2enr | 4 # Enable port A
|
||||
self.write_memory_u32(0x40021018, apb2enr)
|
||||
self.write_memory_u32(0x4002100c, 4)
|
||||
self.write_memory_u32(0x4002100c, 0)
|
||||
self.write_memory_u32(GPIOA+0x0c, 0xffffffff) # ODR
|
||||
self.write_memory_u32(GPIOA+0x04, 0x88888883) # CRH
|
||||
|
||||
# For FST-01-00
|
||||
def blink_led(self):
|
||||
self.write_memory_u32(GPIOA+0x0c, 0xfffffeff) # ODR
|
||||
time.sleep(0.5)
|
||||
self.write_memory_u32(GPIOA+0x0c, 0xffffffff) # ODR
|
||||
time.sleep(0.5)
|
||||
self.write_memory_u32(GPIOA+0x0c, 0xfffffeff) # ODR
|
||||
time.sleep(0.5)
|
||||
self.write_memory_u32(GPIOA+0x0c, 0xffffffff) # ODR
|
||||
|
||||
def protection(self):
|
||||
return (self.read_memory_u32(FLASH_OBR) & 0x0002) != 0
|
||||
|
||||
def option_bytes_read(self):
|
||||
return self.read_memory_u32(OPTION_BYTES_ADDR)
|
||||
|
||||
def option_bytes_write(self,addr,val):
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY2)
|
||||
self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR)
|
||||
|
||||
self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY2)
|
||||
|
||||
prog = gen_prog_option_bytes_write(addr,val)
|
||||
self.write_memory(SRAM_ADDRESS, prog)
|
||||
self.write_reg(15, SRAM_ADDRESS)
|
||||
self.run()
|
||||
i = 0
|
||||
while self.get_status() == 0x80:
|
||||
time.sleep(0.050)
|
||||
i = i + 1
|
||||
if i >= 10:
|
||||
print "ERROR: option bytes write timeout"
|
||||
break
|
||||
|
||||
status = self.read_memory_u32(FLASH_SR)
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK)
|
||||
if (status & FLASH_SR_EOP) == 0:
|
||||
print "ERROR: option bytes write error"
|
||||
|
||||
def option_bytes_erase(self):
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY2)
|
||||
self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR)
|
||||
|
||||
self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY2)
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_OPTER)
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_STRT | FLASH_CR_OPTER)
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
status = self.read_memory_u32(FLASH_SR)
|
||||
if (status & FLASH_SR_BSY) == 0:
|
||||
break
|
||||
i = i + 1
|
||||
if i >= 1000:
|
||||
break
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK)
|
||||
if (status & FLASH_SR_EOP) == 0:
|
||||
raise ValueError, "option bytes erase failed"
|
||||
|
||||
def flash_write_internal(self, addr, data, off, size):
|
||||
prog = gen_prog_flash_write(addr,size)
|
||||
self.write_memory(SRAM_ADDRESS, prog+data[off:off+size])
|
||||
self.write_reg(15, SRAM_ADDRESS)
|
||||
self.run()
|
||||
i = 0
|
||||
while self.get_status() == 0x80:
|
||||
time.sleep(0.050)
|
||||
i = i + 1
|
||||
if i >= BLOCK_WRITE_TIMEOUT:
|
||||
print "ERROR: flash write timeout"
|
||||
break
|
||||
status = self.read_memory_u32(FLASH_SR)
|
||||
if (status & FLASH_SR_PGERR) != 0:
|
||||
print "ERROR: write to a location that was not erased"
|
||||
if (status & FLASH_SR_WRPRTERR) != 0:
|
||||
print "ERROR: write to a location that was write protected"
|
||||
|
||||
def flash_write(self, addr, data):
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY2)
|
||||
self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR)
|
||||
|
||||
off = 0
|
||||
while True:
|
||||
if len(data[off:]) > BLOCK_SIZE:
|
||||
size = BLOCK_SIZE
|
||||
self.flash_write_internal(addr, data, off, size)
|
||||
off = off + size
|
||||
addr = addr + size
|
||||
else:
|
||||
size = len(data[off:])
|
||||
self.flash_write_internal(addr, data, off, size)
|
||||
break
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK)
|
||||
|
||||
def flash_erase_all(self):
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY2)
|
||||
self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR)
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_MER)
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER)
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
status = self.read_memory_u32(FLASH_SR)
|
||||
if (status & FLASH_SR_BSY) == 0:
|
||||
break
|
||||
i = i + 1
|
||||
time.sleep(0.050)
|
||||
if i >= 100:
|
||||
break
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK)
|
||||
|
||||
if (status & FLASH_SR_EOP) == 0:
|
||||
raise ValueError, "flash erase all failed"
|
||||
|
||||
def flash_erase_page(self, addr):
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY1)
|
||||
self.write_memory_u32(FLASH_KEYR, FLASH_KEY2)
|
||||
|
||||
self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR)
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_PER)
|
||||
self.write_memory_u32(FLASH_AR, addr)
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER)
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
status = self.read_memory_u32(FLASH_SR)
|
||||
if (status & FLASH_SR_BSY) == 0:
|
||||
break
|
||||
i = i + 1
|
||||
if i >= 1000:
|
||||
break
|
||||
|
||||
self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK)
|
||||
|
||||
if (status & FLASH_SR_EOP) == 0:
|
||||
raise ValueError, "flash page erase failed"
|
||||
|
||||
def start(self):
|
||||
mode = self.stl_mode()
|
||||
if mode == 2:
|
||||
return
|
||||
elif mode != 1:
|
||||
self.exit_from_dfu()
|
||||
mode = self.stl_mode()
|
||||
print "Change mode to: %04x" % mode
|
||||
self.enter_swd()
|
||||
s = self.get_status()
|
||||
print "Status: %04x" % s
|
||||
if self.stl_mode() != 2:
|
||||
raise ValueError, "Failed to switch debug mode"
|
||||
|
||||
|
||||
USB_VENDOR_ST=0x0483 # 0x0483 SGS Thomson Microelectronics
|
||||
USB_VENDOR_STLINKV2=0x3748 # 0x3748 ST-LINK/V2
|
||||
|
||||
def stlinkv2_devices():
|
||||
busses = usb.busses()
|
||||
for bus in busses:
|
||||
devices = bus.devices
|
||||
for dev in devices:
|
||||
if dev.idVendor != USB_VENDOR_ST:
|
||||
continue
|
||||
if dev.idProduct != USB_VENDOR_STLINKV2:
|
||||
continue
|
||||
yield dev
|
||||
|
||||
def compare(data_original, data_in_device):
|
||||
i = 0
|
||||
for d in data_original:
|
||||
if ord(d) != data_in_device[i]:
|
||||
raise ValueError, "verify failed at %08x" % i
|
||||
i += 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
erase = False
|
||||
if sys.argv[1] == '-e':
|
||||
erase = True
|
||||
sys.argv.pop(1)
|
||||
|
||||
no_protect = False
|
||||
if sys.argv[1] == '-n':
|
||||
no_protect = True
|
||||
sys.argv.pop(1)
|
||||
|
||||
status_only = False
|
||||
unlock = False
|
||||
if sys.argv[1] == '-u':
|
||||
unlock = True
|
||||
sys.argv.pop(1)
|
||||
elif sys.argv[1] == '-s':
|
||||
status_only = True
|
||||
else:
|
||||
filename = sys.argv[1]
|
||||
f = open(filename)
|
||||
data = f.read()
|
||||
f.close()
|
||||
|
||||
for d in stlinkv2_devices():
|
||||
try:
|
||||
stl = stlinkv2(d)
|
||||
print "Device: ", d.filename
|
||||
break
|
||||
except:
|
||||
pass
|
||||
stl.start()
|
||||
core_id = stl.core_id()
|
||||
chip_id = stl.read_memory_u32(0xE0042000)
|
||||
# FST-01 chip id: 0x20036410
|
||||
print "CORE: %08x, CHIP_ID: %08x" % (core_id, chip_id)
|
||||
print "Flash ROM read protection:",
|
||||
protection = stl.protection()
|
||||
if protection:
|
||||
print "ON"
|
||||
if status_only:
|
||||
print "The MCU is now stopped. No way to run by STLink/V2. Please reset the board"
|
||||
exit (0)
|
||||
elif not unlock:
|
||||
print "Please unlock flash ROM protection, at first. By invoking with -u option"
|
||||
exit(1)
|
||||
else:
|
||||
print "off"
|
||||
if status_only:
|
||||
stl.reset_sys()
|
||||
stl.run()
|
||||
stl.exit_debug()
|
||||
exit (0)
|
||||
elif unlock:
|
||||
print "No need to unlock. Protection is not enabled."
|
||||
exit(1)
|
||||
|
||||
print "status: %02x" % stl.get_status()
|
||||
stl.enter_debug()
|
||||
|
||||
if unlock:
|
||||
stl.reset_sys()
|
||||
stl.option_bytes_write(OPTION_BYTES_ADDR,RDP_KEY)
|
||||
print "Flash ROM read protection disabled. Reset the board, now."
|
||||
exit(0)
|
||||
|
||||
print "option bytes: %08x" % stl.option_bytes_read()
|
||||
|
||||
if erase:
|
||||
print "ERASE ALL"
|
||||
stl.reset_sys()
|
||||
stl.flash_erase_all()
|
||||
time.sleep(0.100)
|
||||
|
||||
print "WRITE"
|
||||
stl.flash_write(0x08000000, data)
|
||||
|
||||
print "VERIFY"
|
||||
data_received = ()
|
||||
size = len(data)
|
||||
off = 0
|
||||
while size > 0:
|
||||
if size > 1024:
|
||||
blk_size = 1024
|
||||
else:
|
||||
blk_size = size
|
||||
data_received = data_received + stl.read_memory(0x08000000+off, 1024)
|
||||
size = size - blk_size
|
||||
off = off + blk_size
|
||||
compare(data, data_received)
|
||||
|
||||
if not no_protect:
|
||||
print "PROTECT"
|
||||
stl.option_bytes_erase()
|
||||
print "Flash ROM read protection enabled. Reset the board to enable protection."
|
||||
Reference in New Issue
Block a user