diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml new file mode 100644 index 00000000..0bebd43f --- /dev/null +++ b/.github/workflows/build-and-upload.yml @@ -0,0 +1,36 @@ +name: build and upload + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Use embedded toolchain + - uses: numworks/setup-arm-toolchain@2020-q4 + + # Runs a single command using the runners shell + - name: Build + run: make + + - name: Archive firmware build artifacts as a zip + uses: actions/upload-artifact@v2.2.4 + with: + name: blackmagic-firmware.zip + path: src/blackmagic* + if-no-files-found: error diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml new file mode 100644 index 00000000..a64ec3f2 --- /dev/null +++ b/.github/workflows/build-pr.yml @@ -0,0 +1,29 @@ +name: build PR + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Use embedded toolchain + - uses: numworks/setup-arm-toolchain@2020-q4 + + # Runs a single command using the runners shell + - name: Build + run: make diff --git a/scripts/bootprog.py b/scripts/bootprog.py index 5baf82b0..968fcd68 100755 --- a/scripts/bootprog.py +++ b/scripts/bootprog.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1 # Copyright (C) 2011 Black Sphere Technologies @@ -34,95 +34,93 @@ class stm32_boot: def _sync(self): # Send sync byte - #print "sending sync byte" - self.serial.write("\x7F") + #print("sending sync byte") + self.serial.write(bytes((0x7F,))) self._checkack() def _sendcmd(self, cmd): - if type(cmd) == int: - cmd = chr(cmd) - cmd += chr(ord(cmd) ^ 0xff) - #print "sendcmd:", repr(cmd) + cmd = bytes((cmd, cmd ^ 0xff)) + #print("sendcmd:", repr(cmd)) self.serial.write(cmd) def _send(self, data): csum = 0 - for c in data: csum ^= ord(c) - data = data + chr(csum) - #print "sending:", repr(data) + for c in data: csum ^= c + data = data + bytes((csum,)) + #print("sending:", repr(data)) self.serial.write(data) def _checkack(self): - ACK = "\x79" + ACK = bytes((0x79,)) b = self.serial.read(1) if b != ACK: raise Exception("Invalid ack: %r" % b) - #print "got ack!" + #print("got ack!") def get(self): - self._sendcmd("\x00") + self._sendcmd(0x00) self._checkack() - num = ord(self.serial.read(1)) + num = self.serial.read(1)[0] data = self.serial.read(num+1) self._checkack() return data def eraseall(self): # Send erase cmd - self._sendcmd("\x43") + self._sendcmd(0x43) self._checkack() # Global erase - self._sendcmd("\xff") + self._sendcmd(0xff) self._checkack() def read(self, addr, len): # Send read cmd - self._sendcmd("\x11") + self._sendcmd(0x11) self._checkack() # Send address self._send(struct.pack(">L", addr)) self._checkack() # Send length - self._sendcmd(chr(len-1)) + self._sendcmd(len-1) self._checkack() return self.serial.read(len) def write(self, addr, data): # Send write cmd - self._sendcmd("\x31") + self._sendcmd(0x31) self._checkack() # Send address self._send(struct.pack(">L", addr)) self._checkack() # Send data - self._send(chr(len(data)-1) + data) + self._send(bytes((len(data)-1,)) + data) self._checkack() def write_protect(self, sectors): # Send WP cmd - self._sendcmd("\x63") + self._sendcmd(0x63) self._checkack() # Send sector list - self._send(chr(len(sectors)-1) + "".join(chr(i) for i in sectors)) + self._send(bytes((len(sectors)-1,)) + bytes(sectors)) self._checkack() # Resync after system reset self._sync() def write_unprotect(self): - self._sendcmd("\x73") + self._sendcmd(0x73) self._checkack() self._checkack() self._sync() def read_protect(self): - self._sendcmd("\x82") + self._sendcmd(0x82) self._checkack() self._checkack() self._sync() def read_unprotect(self): - self._sendcmd("\x92") + self._sendcmd(0x92) self._checkack() self._checkack() self._sync() @@ -132,7 +130,7 @@ if __name__ == "__main__": from sys import stdout, argv, platform from getopt import getopt - if platform == "linux2": + if platform == "linux": print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print("STM32 SystemMemory Production Programmer -- version 1.1") print("Copyright (C) 2011 Black Sphere Technologies") @@ -162,7 +160,7 @@ if __name__ == "__main__": boot = stm32_boot(dev, baud) cmds = boot.get() - print("Target bootloader version: %d.%d\n" % (ord(cmds[0]) >> 4, ord(cmds[0]) % 0xf)) + print("Target bootloader version: %d.%d\n" % (cmds[0] >> 4, cmds[0] % 0xf)) print("Removing device protection...") boot.read_unprotect() diff --git a/scripts/dfu-convert.py b/scripts/dfu-convert.py index 63240724..abc0cdda 100755 --- a/scripts/dfu-convert.py +++ b/scripts/dfu-convert.py @@ -1,19 +1,13 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Written by Antonio Galea - 2010/11/18 # Distributed under Gnu LGPL 3.0 # see http://www.gnu.org/licenses/lgpl-3.0.txt -# -# Add support for Python 3 inspired by script found in Bitcraze repository import sys,struct,zlib,os from optparse import OptionParser from intelhex import IntelHex -python3 = False -if (sys.version_info > (3, 0)): - python3 = True - DEFAULT_DEVICE="0x0483:0xdf11" def named(tuple,names): @@ -22,7 +16,7 @@ def consume(fmt,data,names): n = struct.calcsize(fmt) return named(struct.unpack(fmt,data[:n]),names),data[n:] def cstring(string): - return string.split('\0',1)[0] + return string.split(b'\0',1)[0] def compute_crc(data): return 0xFFFFFFFF & -zlib.crc32(data) -1 @@ -31,15 +25,15 @@ def parse(file,dump_images=False): data = open(file,'rb').read() crc = compute_crc(data[:-4]) prefix, data = consume('<5sBIB',data,'signature version size targets') - print('%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) + print('%(signature)r v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) for t in range(prefix['targets']): tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') tprefix['num'] = t if tprefix['named']: tprefix['name'] = cstring(tprefix['name']) else: - tprefix['name'] = '' - print('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix) + tprefix['name'] = b'' + print('%(signature)r %(num)d, alt setting: %(altsetting)r, name: %(name)r, size: %(size)d, elements: %(elements)d' % tprefix) tsize = tprefix['size'] target, data = data[:tsize], data[tsize:] for e in range(tprefix['elements']): @@ -55,7 +49,7 @@ def parse(file,dump_images=False): if len(target): print("target %d: PARSE ERROR" % t) suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') - print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix) + print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)r, %(len)d, 0x%(crc)08x' % suffix) if crc != suffix['crc']: print("CRC ERROR: computed crc32 is 0x%08x" % crc) data = data[16:] @@ -63,30 +57,20 @@ def parse(file,dump_images=False): print("PARSE ERROR") def build(file,targets,device=DEFAULT_DEVICE): - data = '' - if (python3): - data = b'' + data = b'' for t,target in enumerate(targets): - tdata = '' - if (python3): - tdata = b'' + tdata = b'' for image in target: tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] - trgt = 'Target' - st = 'ST...' - if (python3): - trgt = b'Target' - st = b'ST...' + trgt = b'Target' + st = b'ST...' tdata = struct.pack('<6sBI255s2I',trgt,0,1,st,len(tdata),len(target)) + tdata data += tdata - dfu_se = 'DfuSe' - ufd = 'UFD' - if (python3): - dfu_se = b'DfuSe' - ufd = b'UFD' - data = struct.pack('<5sBIB',dfu_se,1,len(data)+11,len(targets)) + data + dfu_se = b'DfuSe' + ufd = b'UFD' + data = struct.pack('<5sBIB',dfu_se,1,len(data)+11,len(targets)) + data v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) data += struct.pack('<4H3sB',0,d,v,0x011a,ufd,16) diff --git a/scripts/dfu.py b/scripts/dfu.py index 170f2d2a..3a6fa752 100644 --- a/scripts/dfu.py +++ b/scripts/dfu.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # dfu.py: Access USB DFU class devices # Copyright (C) 2009 Black Sphere Technologies @@ -62,7 +62,7 @@ DFU_STATUS_ERROR_POR = 0x0d DFU_STATUS_ERROR_UNKNOWN = 0x0e DFU_STATUS_ERROR_STALLEDPKT = 0x0f -class dfu_status(object): +class dfu_status: def __init__(self, buf): self.bStatus = buf[0] self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16) @@ -70,7 +70,7 @@ class dfu_status(object): self.iString = buf[5] -class dfu_device(object): +class dfu_device: def __init__(self, dev, conf, iface): self.dev = dev self.conf = conf diff --git a/scripts/gdb.py b/scripts/gdb.py index 6c6e02d0..30fa20f4 100644 --- a/scripts/gdb.py +++ b/scripts/gdb.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # gdb.py: Python module for low level GDB protocol implementation # Copyright (C) 2009 Black Sphere Technologies @@ -152,7 +152,7 @@ class Target: """Read length bytes from target at address addr""" ret = b'' while length: - # print "Read" + # print("Read") packlen = min(length,self.PacketSize//2) self.putpacket(b"m%08X,%08X" % (addr, packlen)) reply = self.getpacket() @@ -188,11 +188,11 @@ class Target: self.putpacket(b"g") reply = self.getpacket() if (reply == b'') or (reply[:1] == b'E'): - raise Exception('Error reading memory at 0x%08X' % addr) + raise Exception('Error reading target core registers') try: data = unhexify(reply) except Exception: - raise Exception('Invalid response to memory read packet: %r' % reply) + raise Exception('Invalid response to registers read packet: %r' % reply) ret = array.array('I',data) return ret @@ -292,7 +292,7 @@ class Target: addr = self.offset + self.blocksize * i if data is None: continue - #print "Erasing flash at 0x%X" % (self.offset + self.blocksize*i) + #print("Erasing flash at 0x%X" % (self.offset + self.blocksize*i)) self.target.putpacket(b"vFlashErase:%08X,%08X" % (self.offset + self.blocksize*i, self.blocksize)) if self.target.getpacket() != b'OK': @@ -301,7 +301,7 @@ class Target: while data: d = data[0:980] data = data[len(d):] - #print "Writing %d bytes at 0x%X" % (len(d), addr) + #print("Writing %d bytes at 0x%X" % (len(d), addr)) self.target.putpacket(b"vFlashWrite:%08X:%s" % (addr, d)) addr += len(d) if self.target.getpacket() != b'OK': diff --git a/scripts/get_openocd_nrf51_ids.py b/scripts/get_openocd_nrf51_ids.py index 33bdd60e..a141f4fe 100755 --- a/scripts/get_openocd_nrf51_ids.py +++ b/scripts/get_openocd_nrf51_ids.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 """Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for pasting into blackmagic's nrf51.c @@ -21,11 +21,11 @@ specdict = {} specs = [] spec = Spec() for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): - m = re.search('/\*(.*)\*/',line) + m = re.search(r'/\*(.*)\*/',line) if m: lastcomment=m.group(1) - m = re.search('NRF51_DEVICE_DEF\((0x[0-9A-F]*),\s*"(.*)",\s*"(.*)",\s*"(.*)",\s*([0-9]*)\s*\),', line) + m = re.search(r'NRF51_DEVICE_DEF\((0x[0-9A-F]*),\s*"(.*)",\s*"(.*)",\s*"(.*)",\s*([0-9]*)\s*\),', line) if m: spec.hwid = int(m.group(1), base=0) spec.variant = m.group(3) diff --git a/scripts/hexprog.py b/scripts/hexprog.py index 43f9693e..c9356d1c 100755 --- a/scripts/hexprog.py +++ b/scripts/hexprog.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # hexprog.py: Python application to flash a target with an Intel hex file # Copyright (C) 2011 Black Sphere Technologies @@ -18,7 +18,6 @@ # along with this program. If not, see . import gdb -import struct import time # Microcode sequence to erase option bytes @@ -35,7 +34,7 @@ def flash_write_hex(target, hexfile, progress_cb=None): raise Exception("Error in hex file") reclen = int(line[1:3], 16) addrlo = int(line[3:7], 16) - rectype = int(line[7:9], 16); + rectype = int(line[7:9], 16) if sum(x for x in bytes.fromhex(line[1:11+reclen*2])) & 0xff != 0: raise Exception("Checksum error in hex file") if rectype == 0: # Data record @@ -65,8 +64,8 @@ if __name__ == "__main__": from sys import argv, platform, stdout from getopt import getopt - if platform == "linux2": - print ("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen + if platform == "linux": + print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print("Black Magic Probe -- Target Production Programming Tool -- version 1.0") print("Copyright (C) 2011 Black Sphere Technologies") print("License GPLv3+: GNU GPL version 3 or later ") diff --git a/scripts/stm32_mem.py b/scripts/stm32_mem.py index 9f47df31..a33c12ff 100755 --- a/scripts/stm32_mem.py +++ b/scripts/stm32_mem.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # stm32_mem.py: STM32 memory access using USB DFU class # Copyright (C) 2011 Black Sphere Technologies @@ -21,10 +21,9 @@ from time import sleep import struct import os -from sys import stdout, argv +from sys import stdout import argparse -import usb import dfu CMD_GETCOMMANDS = 0x00 @@ -86,7 +85,7 @@ def stm32_scan(args, test): bmp_devs = [] bmp = 0 if not devs: - if test == True: + if test: return print("No DFU devices found!") @@ -107,14 +106,14 @@ def stm32_scan(args, test): bmp_devs.append(dev) if bmp == 0: - if test == True: + if test: return print("No compatible device found\n") exit(-1) if bmp > 1 and not args.serial_target: - if test == True: + if test: return print("Found multiple devices:\n") @@ -129,7 +128,7 @@ def stm32_scan(args, test): print("Serial:\t\t %s\n" % serial_no) print("Select device with serial number!") - exit (-1) + exit(-1) for dev in bmp_devs: dfudev = dfu.dfu_device(*dev) @@ -171,7 +170,7 @@ if __name__ == "__main__": try: state = dfudev.get_state() except: - if args.manifest : exit(0) + if args.manifest: exit(0) print("Failed to read device state! Assuming APP_IDLE") state = dfu.STATE_APP_IDLE if state == dfu.STATE_APP_IDLE: @@ -182,15 +181,15 @@ if __name__ == "__main__": dfudev.release() print("Invoking DFU Device") timeout = 0 - while True : + while True: sleep(1) timeout = timeout + 0.5 dfudev = stm32_scan(args, True) if dfudev: break - if timeout > 5 : + if timeout > 5: print("Error: DFU device did not appear") exit(-1) - if args.manifest : + if args.manifest: stm32_manifest(dfudev) print("Invoking Application Device") exit(0) @@ -203,16 +202,16 @@ if __name__ == "__main__": bin = file.read() product = dfudev.handle.getString(dfudev.dev.iProduct, 64).decode('utf8') - if args.address : + if args.address: start = int(args.address, 0) - else : + else: if "F4" in product or "STLINK-V3" in product: start = 0x8004000 else: start = 0x8002000 addr = start while bin: - print ("Programming memory at 0x%08X" % addr, end="\r") + print("Programming memory at 0x%08X" % addr, end="\r") stdout.flush() try: # STM DFU bootloader erases always. @@ -243,19 +242,19 @@ if __name__ == "__main__": except: # Abort silent if bootloader does not support upload break - print ("Verifying memory at 0x%08X" % addr, end="\r") + print("Verifying memory at 0x%08X" % addr, end="\r") stdout.flush() - if len > 1024 : + if len > 1024: size = 1024 - else : + else: size = len - if bin[:size] != bytearray(data[:size]) : - print ("\nMismatch in block at 0x%08X" % addr) - break; + if bin[:size] != bytearray(data[:size]): + print("\nMismatch in block at 0x%08X" % addr) + break bin = bin[1024:] addr += 1024 len -= 1024 - if len <= 0 : + if len <= 0: print("\nVerified!") stm32_manifest(dfudev) diff --git a/src/Makefile b/src/Makefile index b3f6f7ac..b6930f27 100644 --- a/src/Makefile +++ b/src/Makefile @@ -31,6 +31,7 @@ SRC = \ gdb_hostio.c \ gdb_packet.c \ hex_utils.c \ + jtag_devs.c \ jtag_scan.c \ lmi.c \ lpc_common.c \ diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index f3e3248b..6ba2d781 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -73,7 +73,7 @@ ifneq ($(HOSTED_BMP_ONLY), 1) endif VPATH += platforms/pc -SRC += timing.c cl_utils.c utils.c jtag_devs.c +SRC += timing.c cl_utils.c utils.c SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c ifneq ($(HOSTED_BMP_ONLY), 1) SRC += bmp_libusb.c stlinkv2.c diff --git a/src/platforms/hosted/bmp_libusb.c b/src/platforms/hosted/bmp_libusb.c index 21ed9542..79d4a85b 100644 --- a/src/platforms/hosted/bmp_libusb.c +++ b/src/platforms/hosted/bmp_libusb.c @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright(C) 2020 - 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * Copyright(C) 2020 - 2022 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -146,7 +146,6 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) char serial[64]; char manufacturer[128]; char product[128]; - bmp_type_t type; bool access_problems = false; char *active_cable = NULL; bool ftdi_unknown = false; @@ -159,7 +158,7 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) active_cable = NULL; ftdi_unknown = false; for (int i = 0; devs[i]; i++) { - type = BMP_TYPE_NONE; + bmp_type_t type = BMP_TYPE_NONE; libusb_device *dev = devs[i]; int res = libusb_get_device_descriptor(dev, &desc); if (res < 0) { @@ -299,7 +298,7 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) } if ((found_debuggers == 0) && ftdi_unknown) DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c \" !\n"); - if ((found_debuggers == 1) && !cl_opts->opt_cable && (type == BMP_TYPE_LIBFTDI)) + if ((found_debuggers == 1) && !cl_opts->opt_cable && (info->bmp_type == BMP_TYPE_LIBFTDI)) cl_opts->opt_cable = active_cable; if (!found_debuggers && cl_opts->opt_list_only) DEBUG_WARN("No usable debugger found\n"); diff --git a/src/platforms/hosted/libftdi_swdptap.c b/src/platforms/hosted/libftdi_swdptap.c index 4878437f..3bf69898 100644 --- a/src/platforms/hosted/libftdi_swdptap.c +++ b/src/platforms/hosted/libftdi_swdptap.c @@ -305,7 +305,10 @@ static uint32_t swdptap_seq_in(int ticks) if (do_mpsse) { uint8_t DO[4]; libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks); - for (int i = 0; i < (ticks >> 3) + (ticks & 7)? 1: 0; i++) { + int bytes = ticks >> 3; + if (ticks & 7) + bytes++; + for (int i = 0; i < bytes; i++) { result |= DO[i] << (8 * i); } } else { diff --git a/src/platforms/hosted/remote_jtagtap.c b/src/platforms/hosted/remote_jtagtap.c index a5aa3b6c..8a0d91ae 100644 --- a/src/platforms/hosted/remote_jtagtap.c +++ b/src/platforms/hosted/remote_jtagtap.c @@ -126,26 +126,21 @@ static void jtagtap_tdi_tdo_seq( chunk = 64; } ticks -= chunk; - uint8_t di[8]; - memset(di, 0, 8); + uint64_t di = 0; int bytes = (chunk + 7) >> 3; + int i = 0; if (DI) { - memcpy(&di, DI, bytes); - int remainder = chunk & 7; - DI += bytes; - DI += bytes; - if (remainder) { - uint8_t rem = *DI; - rem &= (1 << remainder) - 1; - *di = rem; + for (; i < bytes; i++) { + di |= *DI << (i * 8); + DI++; } - }; + } /* PRIx64 differs with system. Use it explicit in the format string*/ s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "!J%c%02x%" PRIx64 "%c", (!ticks && final_tms) ? REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS, - chunk, *(uint64_t*)di, REMOTE_EOM); + chunk, di, REMOTE_EOM); platform_buffer_write(construct,s); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); @@ -156,8 +151,10 @@ static void jtagtap_tdi_tdo_seq( } if (DO) { uint64_t res = remotehston(-1, (char *)&construct[1]); - memcpy(DO, &res, bytes); - DO += bytes; + for (i = bytes; i > 0; i--) { + *DO++ = res & 0xff; + res >>= 8; + } } } } diff --git a/src/platforms/hosted/stlinkv2.c b/src/platforms/hosted/stlinkv2.c index 42e81dd9..1ecae9f5 100644 --- a/src/platforms/hosted/stlinkv2.c +++ b/src/platforms/hosted/stlinkv2.c @@ -1010,7 +1010,7 @@ int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == dev_descr[j].idcode) { if(dev_descr[j].handler) - dev_descr[j].handler(&jtag_devs[i]); + dev_descr[j].handler(i, dev_descr[j].idcode); break; } diff --git a/src/platforms/hydrabus/Makefile.inc b/src/platforms/hydrabus/Makefile.inc index e2f8f395..9d62f2df 100644 --- a/src/platforms/hydrabus/Makefile.inc +++ b/src/platforms/hydrabus/Makefile.inc @@ -27,7 +27,7 @@ all: blackmagic.bin blackmagic.hex blackmagic.dfu: blackmagic.hex @echo Creating $@ - @python ../scripts/dfu-convert.py -i $< $@ + @python3 ../scripts/dfu-convert.py -i $< $@ host_clean: -$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu diff --git a/src/platforms/swlink/README.md b/src/platforms/swlink/README.md index edfbb9e6..1a9cceb3 100644 --- a/src/platforms/swlink/README.md +++ b/src/platforms/swlink/README.md @@ -11,7 +11,7 @@ | SRST | PB4 | CN5/8 | P4/9 (40) | | UART1_TX | PB6 | CN7/4 | P4/7 (42) | | UART1_RX | PB7 | CN7/2 | P4/6 (43) | -| SWO/RX2 | PA3 | NA(*1) | P3/7 (13) | +| SWO/RX2 | PA3 | NA(*1) | P3/8 (13) | *1: Wire JTDO/PB3 (U2/39) to USART2_RX/PA3 (U2/13) to expose SWO for Stlink on STM8S-Disco on CN5/3 diff --git a/src/target/adiv5.h b/src/target/adiv5.h index 95c62f62..bcaa1921 100644 --- a/src/target/adiv5.h +++ b/src/target/adiv5.h @@ -89,23 +89,19 @@ #define ADIV5_AP_BASE ADIV5_AP_REG(0xF8) #define ADIV5_AP_IDR ADIV5_AP_REG(0xFC) -/* Known designers seen in SYSROM-PIDR and JTAG IDCode. - * Ignore Bit 0 from the designer bits to get JEDEC Ids. - * Should get it's one file as not only related to Adiv5! - */ +/* Known designers seen in SYSROM-PIDR. Ignore Bit 0 from + * the designer bits to get JEDEC Ids with bit 7 ignored.*/ #define AP_DESIGNER_FREESCALE 0x00e #define AP_DESIGNER_TEXAS 0x017 #define AP_DESIGNER_ATMEL 0x01f #define AP_DESIGNER_STM 0x020 #define AP_DESIGNER_CYPRESS 0x034 #define AP_DESIGNER_INFINEON 0x041 -#define DESIGNER_XILINX 0x049 #define AP_DESIGNER_NORDIC 0x244 #define AP_DESIGNER_ARM 0x43b /*LPC845 with designer 501. Strange!? */ #define AP_DESIGNER_SPECULAR 0x501 #define AP_DESIGNER_CS 0x555 -#define DESIGNER_XAMBALA 0x61e #define AP_DESIGNER_ENERGY_MICRO 0x673 #define AP_DESIGNER_GIGADEVICE 0x751 #define AP_DESIGNER_RASPBERRY 0x927 @@ -289,7 +285,7 @@ void adiv5_ap_ref(ADIv5_AP_t *ap); void adiv5_ap_unref(ADIv5_AP_t *ap); void platform_add_jtag_dev(const int dev_index, const jtag_dev_t *jtag_dev); -void adiv5_jtag_dp_handler(jtag_dev_t *jd); +void adiv5_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode); int platform_jtag_dp_init(ADIv5_DP_t *dp); int swdptap_init(ADIv5_DP_t *dp); diff --git a/src/target/adiv5_jtagdp.c b/src/target/adiv5_jtagdp.c index 52737461..2c87dc7c 100644 --- a/src/target/adiv5_jtagdp.c +++ b/src/target/adiv5_jtagdp.c @@ -39,7 +39,7 @@ static uint32_t adiv5_jtagdp_error(ADIv5_DP_t *dp); -void adiv5_jtag_dp_handler(jtag_dev_t *jd) +void adiv5_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) { ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); if (!dp) { /* calloc failed: heap exhaustion */ @@ -47,8 +47,8 @@ void adiv5_jtag_dp_handler(jtag_dev_t *jd) return; } - dp->dp_jd_index = jd->jd_dev; - dp->idcode = jd->jd_idcode; + dp->dp_jd_index = jd_index; + dp->idcode = j_idcode; if ((PC_HOSTED == 0 ) || (!platform_jtag_dp_init(dp))) { dp->dp_read = fw_adiv5_jtagdp_read; dp->error = adiv5_jtagdp_error; diff --git a/src/target/jtag_devs.h b/src/target/jtag_devs.h index 8f877985..8c2c0b5a 100644 --- a/src/target/jtag_devs.h +++ b/src/target/jtag_devs.h @@ -22,7 +22,7 @@ typedef const struct jtag_dev_descr_s { const uint32_t idcode; const uint32_t idmask; const char * const descr; - void (*const handler)(jtag_dev_t *jd); + void (*const handler)(uint8_t jd_index, uint32_t j_idcode); } jtag_dev_descr_t; extern jtag_dev_descr_t dev_descr[]; diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index eb1efc80..761f5ff0 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -3,7 +3,6 @@ * * Copyright (C) 2011 Black Sphere Technologies Ltd. * Written by Gareth McMullin - * Copyright (C) 2021 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +25,16 @@ #include "general.h" #include "jtagtap.h" +#include "jtag_scan.h" #include "target.h" #include "adiv5.h" +#include "jtag_devs.h" -jtag_dev_t jtag_devs[JTAG_MAX_DEVS+1]; +struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; int jtag_dev_count; /* bucket of ones for don't care TDI */ -static const uint8_t ones[] = {0xff, 0xFF, 0xFF, 0xFF}; +static const uint8_t ones[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; #if PC_HOSTED == 0 void jtag_add_device(const int dev_index, const jtag_dev_t *jtag_dev) @@ -46,32 +47,36 @@ void jtag_add_device(const int dev_index, const jtag_dev_t *jtag_dev) #endif /* Scan JTAG chain for devices, store IR length and IDCODE (if present). + * Reset TAP state machine. + * Select Shift-IR state. + * Each device is assumed to shift out IR at 0x01. (this may not always be true) + * Shift in ones until we read two consecutive ones, then we have shifted out the + * IRs of all devices. * - * https://www.fpga4fun.com/JTAG3.html - * Count the number of devices in the JTAG chain - * - * shift enough ones in IR - * shift enough zeros in DR - * Now shift out ones and stop if first '1' is seen. This gets the number - * of devices - * - * Assume max 32 devices with max IR len 16 = 512 bits = 16 loops * 32 bit + * After this process all the IRs are loaded with the BYPASS command. + * Select Shift-DR state. + * Shift in ones and count zeros shifted out. Should be one for each device. + * Check this against device count obtained by IR scan above. * * Reset the TAP state machine again. This should load all IRs with IDCODE. - * Read 32 bit IDCODE for all devices. - */ - + * For each device, shift out one bit. If this is zero IDCODE isn't present, + * continue to next device. If this is one shift out the remaining 31 bits + * of the IDCODE register. + */ int jtag_scan(const uint8_t *irlens) { int i; - void (*jd_handlers[JTAG_MAX_DEVS])(jtag_dev_t *jd); + uint32_t j; + target_list_free(); - memset(jd_handlers, 0, sizeof(jd_handlers)); + jtag_dev_count = 0; + memset(&jtag_devs, 0, sizeof(jtag_devs)); - /* Run throught the SWD to JTAG sequence for the case where an - * attached SWJ-DP is in SW-DP mode. + /* Run throught the SWD to JTAG sequence for the case where an attached SWJ-DP is + * in SW-DP mode. */ + DEBUG_INFO("Resetting TAP\n"); #if PC_HOSTED == 1 if (platform_jtagtap_init()) { DEBUG_WARN("JTAG not available\n"); @@ -81,146 +86,139 @@ int jtag_scan(const uint8_t *irlens) jtagtap_init(); #endif jtag_proc.jtagtap_reset(); -#define LOOPS 16 - jtagtap_shift_ir(); - i = LOOPS; - uint8_t ir_chain[64], *din = ir_chain; - while (i--) { - jtag_proc.jtagtap_tdi_tdo_seq(din, (i == 0) ? 1 : 0, ones, - sizeof(ones) * 8); - din += sizeof(ones); - } - if (!(ir_chain[0] & 1)) { - DEBUG_WARN("Unexpected IR chain!\n"); - return 0; + + if (irlens) { + DEBUG_WARN("Given list of IR lengths, skipping probe\n"); + DEBUG_INFO("Change state to Shift-IR\n"); + jtagtap_shift_ir(); + j = 0; + while((jtag_dev_count <= JTAG_MAX_DEVS) && + (jtag_devs[jtag_dev_count].ir_len <= JTAG_MAX_IR_LEN)) { + uint32_t irout; + if(*irlens == 0) + break; + jtag_proc.jtagtap_tdi_tdo_seq((uint8_t*)&irout, 0, ones, *irlens); + if (!(irout & 1)) { + DEBUG_WARN("check failed: IR[0] != 1\n"); + return -1; + } + jtag_devs[jtag_dev_count].ir_len = *irlens; + jtag_devs[jtag_dev_count].ir_prescan = j; + jtag_devs[jtag_dev_count].jd_dev = jtag_dev_count; + j += *irlens; + irlens++; + jtag_dev_count++; + } + } else { + DEBUG_INFO("Change state to Shift-IR\n"); + jtagtap_shift_ir(); + + DEBUG_INFO("Scanning out IRs\n"); + if(!jtag_proc.jtagtap_next(0, 1)) { + DEBUG_WARN("jtag_scan: Sanity check failed: IR[0] shifted out " + "as 0\n"); + jtag_dev_count = -1; + return -1; /* must be 1 */ + } + jtag_devs[0].ir_len = 1; j = 1; + while((jtag_dev_count <= JTAG_MAX_DEVS) && + (jtag_devs[jtag_dev_count].ir_len <= JTAG_MAX_IR_LEN)) { + if(jtag_proc.jtagtap_next(0, 1)) { + if(jtag_devs[jtag_dev_count].ir_len == 1) break; + jtag_devs[++jtag_dev_count].ir_len = 1; + jtag_devs[jtag_dev_count].ir_prescan = j; + jtag_devs[jtag_dev_count].jd_dev = jtag_dev_count; + } else jtag_devs[jtag_dev_count].ir_len++; + j++; + } + if(jtag_dev_count > JTAG_MAX_DEVS) { + DEBUG_WARN("jtag_scan: Maximum device count exceeded\n"); + jtag_dev_count = -1; + return -1; + } + if(jtag_devs[jtag_dev_count].ir_len > JTAG_MAX_IR_LEN) { + DEBUG_WARN("jtag_scan: Maximum IR length exceeded\n"); + jtag_dev_count = -1; + return -1; + } } + + DEBUG_INFO("Return to Run-Test/Idle\n"); + jtag_proc.jtagtap_next(1, 1); jtagtap_return_idle(); + + /* All devices should be in BYPASS now */ + + /* Count device on chain */ + DEBUG_INFO("Change state to Shift-DR\n"); jtagtap_shift_dr(); - i = LOOPS; - uint8_t zeros[] = {0, 0, 0, 0}; - while(i--) { - jtag_proc.jtagtap_tdi_seq(0, zeros, sizeof(zeros) * 8); - } - int num_devices = 0; - while (!jtag_proc.jtagtap_next(0,1) && (i++ < 6)) - num_devices++; - jtag_proc.jtagtap_reset(); - jtagtap_shift_dr(); - jtag_dev_count = num_devices; - if (!num_devices) - return 0; - DEBUG_TARGET("Found %d devices\n", num_devices); - int irbit = 1; - int j = 0; - for (i = 0; i < num_devices; i++) { - uint8_t id[4]; - jtag_proc.jtagtap_tdi_tdo_seq(id, 0, ones, 32); - if (!(id[0] & 1)) { - DEBUG_WARN("Invalid IDCode!\n"); - return 0; - } - uint32_t idcode = id[3] << 24 | id[2] << 16 | id[1] << 8 | id[0]; - unsigned int designer = ((id[1] & 0xf) << 8) | (id[0] >> 1); - unsigned int product = id[2] | ((id[3] & 0xf) << 8); - unsigned int expected_irlen = 0; - switch (designer) { - case AP_DESIGNER_ARM: - switch (product) { - case 0xba0: - jtag_devs[i].jd_descr = "ADIv5 JTAG-DP port"; - jd_handlers[i] = adiv5_jtag_dp_handler; - expected_irlen = 4; - break; - default: - jtag_devs[i].jd_descr = "ARM"; - } - break; - case AP_DESIGNER_STM: - expected_irlen = 5; - jtag_devs[i].jd_descr = "STM32 BSD"; - break; - case AP_DESIGNER_ATMEL: - if ((product >= 0x940) & (product < 0x990)) { - jtag_devs[i].jd_descr = "ATMEL AVR8"; - expected_irlen = 4; - break; - } - jtag_devs[i].jd_descr = "ATMEL"; - break; - case DESIGNER_XILINX: - if (!irlens) { - /* Guessed irlen for XILINX devices is wrong. - * IR data contains status bits! - */ - DEBUG_WARN("Please provide irlens as chain contains XILINX devices!\n"); - return 0; - } - jtag_devs[i].jd_descr = "XILINX"; - break; - case DESIGNER_XAMBALA: - expected_irlen = 5; - jtag_devs[i].jd_descr = "RVDBG013"; - break; - case AP_DESIGNER_GIGADEVICE: - expected_irlen = 5; - jtag_devs[i].jd_descr = "GIGADEVICE BSD"; - break; - } - if (!jtag_devs[i].jd_descr) { - DEBUG_WARN("Unhandled designer %x\n", designer); - jtag_devs[i].jd_descr = "Unknow"; - } - bool bit; - int guessed_irlen = 0; - int advance = irbit; - do { - /* Guess IR length from the IR scan after JTAG Reset - * First bit should be '1', following bits are '0', if not used - * for instruction capture, as for Xilinx parts. - */ - bit = (ir_chain[advance / 8] & (1 << (advance & 7))); - guessed_irlen++; - advance++; - } while (!bit && (advance < (JTAG_MAX_DEVS * 16))); - if (irlens) { /* Allow to overwrite from the command line!*/ - if (*irlens != guessed_irlen) { - DEBUG_TARGET("Provides irlen %d vs guessed %d for device %d\n", - *irlens, guessed_irlen, i + 1); - } - expected_irlen = *irlens++; - } - if (!expected_irlen) { - expected_irlen = guessed_irlen++; - } - jtag_devs[i].ir_len = expected_irlen; - jtag_devs[i].ir_prescan = j; - jtag_devs[i].jd_dev = i; - jtag_devs[i].jd_idcode = idcode; + for(i = 0; (jtag_proc.jtagtap_next(0, 1) == 0) && (i <= jtag_dev_count); i++) jtag_devs[i].dr_postscan = jtag_dev_count - i - 1; - jtag_devs[i].current_ir = -1; - j += expected_irlen; - irbit += expected_irlen; - DEBUG_INFO("%2d: IDCODE: 0x%08" PRIx32 ", IR len %d %s%s\n", i + 1, - idcode,jtag_devs[i].ir_len, jtag_devs[i].jd_descr, - (jd_handlers[i]) ? "" : " (Unhandled) "); + + if(i != jtag_dev_count) { + DEBUG_WARN("jtag_scan: Sanity check failed: " + "BYPASS dev count doesn't match IR scan\n"); + jtag_dev_count = -1; + return -1; } - jtag_proc.jtagtap_reset(); + + DEBUG_INFO("Return to Run-Test/Idle\n"); + jtag_proc.jtagtap_next(1, 1); + jtagtap_return_idle(); + if(!jtag_dev_count) { + return 0; + } + /* Fill in the ir_postscan fields */ - for(i = jtag_dev_count - 1; i; i--) { + for(i = jtag_dev_count - 1; i; i--) jtag_devs[i-1].ir_postscan = jtag_devs[i].ir_postscan + jtag_devs[i].ir_len; + + /* Reset jtagtap: should take all devs to IDCODE */ + jtag_proc.jtagtap_reset(); + jtagtap_shift_dr(); + for(i = 0; i < jtag_dev_count; i++) { + if(!jtag_proc.jtagtap_next(0, 1)) continue; + jtag_devs[i].jd_idcode = 1; + for(j = 2; j; j <<= 1) + if(jtag_proc.jtagtap_next(0, 1)) jtag_devs[i].jd_idcode |= j; + } + DEBUG_INFO("Return to Run-Test/Idle\n"); + jtag_proc.jtagtap_next(1, 1); + jtagtap_return_idle(); #if PC_HOSTED == 1 /*Transfer needed device information to firmware jtag_devs*/ - for(i = 0; i < jtag_dev_count; i++) { + for(i = 0; i < jtag_dev_count; i++) platform_add_jtag_dev(i, &jtag_devs[i]); + for(i = 0; i < jtag_dev_count; i++) { + DEBUG_INFO("Idcode 0x%08" PRIx32, jtag_devs[i].jd_idcode); + for(j = 0; dev_descr[j].idcode; j++) { + if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == + dev_descr[j].idcode) { + DEBUG_INFO(": %s", + (dev_descr[j].descr) ? dev_descr[j].descr : "unknown"); + break; + } + } + DEBUG_INFO("\n"); } #endif + /* Check for known devices and handle accordingly */ for(i = 0; i < jtag_dev_count; i++) - /* Call handler to initialise/probe device further */ - if (jd_handlers[i]) - jd_handlers[i](&jtag_devs[i]); + for(j = 0; dev_descr[j].idcode; j++) + if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == + dev_descr[j].idcode) { + jtag_devs[i].current_ir = -1; + /* Save description in table */ + jtag_devs[i].jd_descr = dev_descr[j].descr; + /* Call handler to initialise/probe device further */ + if(dev_descr[j].handler) + dev_descr[j].handler(i, dev_descr[i].idcode); + break; + } + return jtag_dev_count; } diff --git a/src/target/jtag_scan.h b/src/target/jtag_scan.h index bc76e0bc..cc6d361a 100644 --- a/src/target/jtag_scan.h +++ b/src/target/jtag_scan.h @@ -40,7 +40,7 @@ typedef struct jtag_dev_s { uint32_t current_ir; } jtag_dev_t; -extern jtag_dev_t jtag_devs[JTAG_MAX_DEVS+1]; +extern struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; extern int jtag_dev_count; void jtag_dev_write_ir(jtag_proc_t *jp, uint8_t jd_index, uint32_t ir); diff --git a/src/target/kinetis.c b/src/target/kinetis.c index 7ac9ffa5..5e44bfe8 100644 --- a/src/target/kinetis.c +++ b/src/target/kinetis.c @@ -373,7 +373,7 @@ do_common_s32k14x: } static bool -kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) +kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items) { uint8_t fstat; @@ -390,8 +390,9 @@ kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) addr |= (uint32_t)cmd << 24; target_mem_write32(t, FTFA_FCCOB_0, addr); if (data) { - target_mem_write32(t, FTFA_FCCOB_1, *(uint32_t*)&data[0]); - target_mem_write32(t, FTFA_FCCOB_2, *(uint32_t*)&data[4]); + target_mem_write32(t, FTFA_FCCOB_1, data[0]); + if (n_items > 1) + target_mem_write32(t, FTFA_FCCOB_2, data[1]); } /* Enable execution by clearing CCIF */ @@ -411,7 +412,7 @@ kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len) { while (len) { - if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL)) { + if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL, 0)) { /* Different targets have different flash erase sizes */ if (len > f->blocksize) len -= f->blocksize; @@ -450,7 +451,7 @@ static int kl_gen_flash_write(struct target_flash *f, } while (len) { - if (kl_gen_command(f->t, write_cmd, dest, src)) { + if (kl_gen_command(f->t, write_cmd, dest, src, 1)) { if (len > kf->write_len) len -= kf->write_len; else @@ -484,12 +485,13 @@ static int kl_gen_flash_done(struct target_flash *f) vals[1] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS); vals[1] = (vals[1] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED; kl_gen_command(f->t, FTFE_CMD_PROGRAM_PHRASE, - FLASH_SECURITY_BYTE_ADDRESS - 4, (uint8_t*)vals); + FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2); } else { - uint32_t vals[2] = {target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS), 0}; + uint32_t vals[1]; + vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS); vals[0] = (vals[0] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED; kl_gen_command(f->t, FTFA_CMD_PROGRAM_LONGWORD, - FLASH_SECURITY_BYTE_ADDRESS, (uint8_t*)&vals); + FLASH_SECURITY_BYTE_ADDRESS, vals, 1); } return 0; diff --git a/src/target/samd.c b/src/target/samd.c index f6134088..6f3c574b 100644 --- a/src/target/samd.c +++ b/src/target/samd.c @@ -715,11 +715,51 @@ static bool samd_set_flashlock(target *t, uint16_t value, const char **argv) return true; } +static bool parse_unsigned(const char *s, uint32_t *val) { + int l, st; + unsigned long num; + + l=strlen(s); + + if (l>2 && s[0]=='0' && (s[1]=='x' || s[1]=='X')) { + st=sscanf(s+2, "%lx", &num); + } else { + st=sscanf(s, "%lu", &num); + } + + if (st<1) { + return false; + } + + *val=(uint32_t)num; + return true; +} + static bool samd_cmd_lock_flash(target *t, int argc, const char **argv) { + unsigned long val; + (void)argc; (void)argv; - return samd_set_flashlock(t, 0x0000, NULL); + + if (argc>2) { + tc_printf(t, "usage: monitor lock_flash [number]\n"); + return false; + } else if (argc==1) { + return samd_set_flashlock(t, 0x0000, NULL); + } else { + if (!parse_unsigned(argv[1], &val)) { + tc_printf(t, "number must be either decimal or 0x prefixed hexadecimal\n"); + return false; + } + + if (val>0xffff) { + tc_printf(t, "number must be between 0 and 0xFFFF\n"); + return false; + } + + return samd_set_flashlock(t, (uint16_t)val, NULL); + } } static bool samd_cmd_unlock_flash(target *t, int argc, const char **argv) @@ -764,9 +804,30 @@ static bool samd_set_bootprot(target *t, uint16_t value, const char **argv) static bool samd_cmd_lock_bootprot(target *t, int argc, const char **argv) { + unsigned long val; + (void)argc; (void)argv; - return samd_set_bootprot(t, 0, NULL); + /* locks first 0x7 .. 0, 0x6 .. 512, 0x5 .. 1024, ..., 0x0 .. 32768 bytes of flash*/ + + if (argc>2) { + tc_printf(t, "usage: monitor lock_bootprot [number]\n"); + return false; + } else if (argc==1) { + return samd_set_bootprot(t, 0, NULL); + } else { + if (!parse_unsigned(argv[1], &val)) { + tc_printf(t, "number must be either decimal or 0x prefixed hexadecimal\n"); + return false; + } + + if (val>7) { + tc_printf(t, "number must be between 0 and 7\n"); + return false; + } + + return samd_set_bootprot(t, (uint16_t)val, NULL); + } } static bool samd_cmd_unlock_bootprot(target *t, int argc, const char **argv)