import hidapi
import struct
import time
+import os.path
+
BSL_VID = 0x2047
BSL_PID = 0x0200
12 34 56 78 99 10 11 12 13 14 15 16 17 18 00 80
q"""
-BLINK_BSL2 = """@2000
+# reta: 10 01; jmp .: ff3f; ret: 3041
+BLINK_BSL3 = """@2400
+B2 40 80 5A 5C 01 E2 43 04 02 E2 43 02 02 2C 43
+3D 40 AD DE 3E 40 EF BE 80 00 02 10
+q"""
+
+RET_BSL = """@2400
+2C 43 3D 40 AD DE 3E 40 EF BE B0 13 02 10
+q"""
+
+BLINK_BSL2 = """@2400
31 40 00 34 B0 13 0C 20 B0 13 32 20 21 83 D2 43
04 02 D2 43 02 02 B2 40 80 5A 5C 01 07 3C 91 53
00 00 B1 93 00 00 FB 23 D2 E3 02 02 81 43 00 00
+def segment_flash(iterator):
+ flash = {}
+ def insert(base, off, data):
+ assert off + len(data) <= 512
+ orig = flash.get(base, "\0" * 512)
+ new = orig[0:off] + data + orig[off+len(data):]
+ flash[base] = new
+ for addr, data in iterator:
+ while len(data) > 0:
+ base = addr >> 9
+ off = addr % 512
+
+ sub, data = data[0:512-off], data[512-off:]
+ addr += len(sub)
+
+ insert(base, off, sub)
+
+ for addr in sorted(flash):
+ yield (addr << 9), flash[addr]
+
class BSL(object):
MSGS = ["SUCCESS",
"Flash write check failed",
return self._send_command(0x15, "")
def CrcCheck(self, addr, length):
return self._send_command(0x16, _fmt_addr(addr) + _fmt_addr(length, 2))
- def LoadPc(self, addr):
- return self._send_command(0x17, _fmt_addr(addr), False)
+ def LoadPc(self, addr, expect_response=False):
+ return self._send_command(0x17, _fmt_addr(addr), expect_response)
def TxDataBlock(self, addr, length):
return self._send_command(0x18, _fmt_addr(addr) + _fmt_addr(length, 2))
def TxBslVersion(self):
return self._send_command(0x1a, "")
# Helpers
+ def RxLargeDatablock(self, addr, data):
+ # We can send at most 64 bytes at once, due to HID limitations.
+ while len(data) > 0:
+ sub, data = data[:64], data[64:]
+ self.RxDataBlockFast(addr, sub)
+ addr += len(sub)
+
def RxTIHexFast(self, hexstring):
tihex = TiHex(hexstring)
for addr, value in tihex:
self.RxDataBlockFast(addr, value)
+ def FlashTIHex(self, hexstring):
+ flash = segment_flash(TiHex(hexstring))
+ sled_path = os.path.join(os.path.dirname(__file__), "shellcode", "bslv2-flasher", "flasher.bin")
+ sled = open(sled_path, "rb").read()
+ for addr, data in flash:
+ # Maybe flash more than one block at a time? We do have 4K of ram
+ payload = struct.pack("<H", addr >> 8) + data
+ cksum = 256 - ((sum(ord(x) for x in "\001" + payload) + 1) % 256)
+ payload = "\001" + chr(cksum) + payload
+
+ assert (sum(ord(x) for x in payload) % 256) == 255
+
+ self.RxLargeDatablock(0x2400, sled + payload)
+ print repr(self.LoadPc(0x2400, True))
+
+
def bounce_hid(self):
"Reconnect to the target"
self.device.close()
#return
try:
print repr(bsl.RxPassword('\xff' * 32))
- print repr(bsl.RxTIHexFast(RAM_BSL))
- print repr(bsl.LoadPc(0x2400))
- #print repr(bsl.RxTIHexFast(file("blinky.tihex","r").read()))
+ #print repr(bsl.FlashTIHex(BLINK_BSL))
+ print repr(bsl.RxTIHexFast(BLINK_BSL2))
#print repr(bsl.LoadPc(0x2000))
+ #raise SystemExit(0)
+ #print repr(bsl.RxTIHexFast(file("blinky.tihex","r").read()))
+ print repr(bsl.LoadPc(0x2400, True))
#bsl.device.close()
print repr("Bouncing...")
time.sleep(3)
finally:
bsl.device.close()
+def mainx():
+ for addr, data in segment_flash(TiHex(RAM_BSL)):
+ bs = 64
+ hexdata = "\n ".join(data[s:s+bs].encode("hex") for s in range(0,len(data),bs))
+ print "%04x %s" % (addr, hexdata)
+
main()
--- /dev/null
+ ;; Org is set at 0 so that there is no padding before the sled.
+ ;; This code should be run from RAM; the address doesn't really matter.
+ BASE == 0x0
+ .org BASE
+ code_size_guess == 0xB2
+ LED_PORT = 0x0200
+ FLASH_LED = 0x02
+ FAIL_LED = 0x04
+
+ ;; MSP430f5510 definitions
+ FCTL1 == 0x0140
+ FCTL3 == 0x0144
+ BUSY == 0x0001
+ FWPW == 0xA500
+ ERASE == 0x0004
+ WRT == 0x0040
+ BLKWRT == 0x0080
+ WAIT == 0x0008
+ LOCK == 0x0010
+
+ ;; Format of payload: (all values MSP-endian)
+ ;; {
+ ;; number of blocks: 1 byte
+ ;; checksum: 1 byte (byte such that two's complement sum of payload bytes == 0xff)
+ ;; repeat: (total of (payload length - 3) bytes)
+ ;; (start_address >> 8): 2 bytes
+ ;; block data: 512 bytes
+ ;; }
+ ;; The shortest possible payload would thus be <<0x00 0xFF>>
+ ;; A payload that writes 0's to 0xFE00-0xFFFF would be:
+ ;; <<0x01 0x00 0xFE 0x00 0x00*512>>
+
+ ;; Assumptions/caveats:
+ ;; 1) Assume RAM is in low memory. It will fail miserably otherwise
+ ;; 2) All this code is very carefully written to be position-independent
+
+ ;; Register usage:
+ ;;
+ ;; r4: start of payload
+ ;; r5: address of start
+start:
+ ;; the next two instructions must be the first two instructions after start
+ mov r0, r5
+ add #(code_size_guess + start - .), r5
+ mov r6, r4
+
+ bis.b #FLASH_LED+FAIL_LED, &LED_PORT+4
+ bic.b #FLASH_LED+FAIL_LED, &LED_PORT+2
+ ;; calc checksum
+ ;; local regs:
+ ;; r6: running sum
+ ;; r7: end addr
+ ;; r8: current addr
+ ;; r9: scratch
+ mov r4, r8
+ mov r4, r7
+ mov.b @r8, r9
+ incd r7
+
+ rla r9, 1 ; Add r9*514 (r9<<1 + r9 << 9)
+ add r9, r7
+ rla r9, 8
+ add r9, r7
+
+ add @r8, r7
+ mov.b #0, r6
+1: add.b @r8+, r6
+ cmp r7, r8
+ jlo 1b
+ cmp #0xff, r6
+
+ bis.b #FAIL_LED, &LED_PORT+2
+ reta
+
+ ;; Get flashing
+ ;; local regs:
+ ;; r6: current src
+ ;; r7: current dest
+ ;; r8: block id
+ ;; r9: block count
+ ;; r10: dwords remaining
+ mov r4, r6
+ clr r8
+ mov.b @r4, r9
+ incd r6
+
+next_block:
+ dec r9
+ jnc done_programming
+ bis #FLASH_LED, &LED_PORT+2
+ ;; calc dest addr
+ mov @r6+, r7
+ rlam.a #4, r7 ; multiply by 256 to recover real address
+ rlam.a #4, r7
+ ;; erase block
+1: bit #BUSY, &FCTL3
+ jnz 1b
+ mov #FWPW, &FCTL3
+ mov #FWPW+ERASE, &FCTL1
+ clr @r7
+1: bit #BUSY, &FCTL3
+ jnz 1b
+
+ ;; not sure whether I need to bounce LOCK here
+ mov #32, r10
+ mov #FWPW+BLKWRT+WRT, &FCTL1
+2: mov @r6+, 0(r7)
+ mov @r6+, 2(r7)
+3: bit #WAIT, &FCTL3
+ jz 3b
+ add #4, r7 ; This was originally 2 incd insns
+ dec r10
+ jnz 2b
+ mov #FWPW, &FCTL1
+4: bit #BUSY, &FCTL3
+ jnz 4b
+
+ mov #FWPW+LOCK, &FCTL3
+ jmp next_block
+
+done_programming:
+ bic.b #FLASH_LED, &LED_PORT+2
+ bic.b #FAIL_LED, &LED_PORT+2
+
+bsl_ret:
+ mov #2, r12
+ mov #0xDEAD, r13
+ mov #0xBEEF, r14
+ bra #0x1002
+
+payload:
+ .data
+ .if (payload-start) != code_size_guess
+
+ .print "Payload guess wrong"
+ .endif
+
+