Merge pull request #561 from UweBonnes/pc_prog

Command line interaction for pc-hosted platforms.
This commit is contained in:
UweBonnes 2019-12-08 16:57:58 +01:00 committed by GitHub
commit 0b6f393d5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1301 additions and 108 deletions

View File

@ -22,6 +22,7 @@
#define __GENERAL_H
#define _GNU_SOURCE
#define __USE_MINGW_ANSI_STDIO 1
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
@ -44,15 +45,5 @@
#undef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#ifdef _WIN32
# ifdef _WIN64
# define PRI_SIZET PRIu64
# else
# define PRI_SIZET PRIu32
# endif
#else
# define PRI_SIZET "zu"
#endif
#endif

View File

@ -8,4 +8,5 @@ else ifneq (, $(findstring cygwin, $(SYS)))
LDFLAGS += -lusb-1.0 -lws2_32
endif
VPATH += platforms/pc
SRC += timing.c \
SRC += timing.c cl_utils.c
CFLAGS +=-I ./target -I./platforms/pc

View File

@ -28,6 +28,8 @@
struct ftdi_context *ftdic;
#include "cl_utils.h"
#define BUF_SIZE 4096
static uint8_t outbuf[BUF_SIZE];
static uint16_t bufptr = 0;
@ -180,29 +182,21 @@ cable_desc_t cable_desc[] = {
void platform_init(int argc, char **argv)
{
int err;
int c;
unsigned index = 0;
char *serial = NULL;
char * cablename = "ftdi";
while((c = getopt(argc, argv, "c:s:")) != -1) {
switch(c) {
case 'c':
cablename = optarg;
break;
case 's':
serial = optarg;
break;
}
}
BMP_CL_OPTIONS_t cl_opts = {0};
cl_opts.opt_idstring = "Blackmagic Debug Probe for FTDI/MPSSE";
cl_opts.opt_cable = "ftdi";
cl_init(&cl_opts, argc, argv);
int err;
unsigned index = 0;
int ret = -1;
for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]);
index++)
if (strcmp(cable_desc[index].name, cablename) == 0)
if (strcmp(cable_desc[index].name, cl_opts.opt_cable) == 0)
break;
if (index == sizeof(cable_desc)/sizeof(cable_desc[0])){
fprintf(stderr, "No cable matching %s found\n",cablename);
fprintf(stderr, "No cable matching %s found\n", cl_opts.opt_cable);
exit(-1);
}
@ -226,32 +220,42 @@ void platform_init(int argc, char **argv)
if((err = ftdi_set_interface(ftdic, active_cable->interface)) != 0) {
fprintf(stderr, "ftdi_set_interface: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
goto error_1;
}
if((err = ftdi_usb_open_desc(
ftdic, active_cable->vendor, active_cable->product,
active_cable->description, serial)) != 0) {
active_cable->description, cl_opts.opt_serial)) != 0) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
err, ftdi_get_error_string(ftdic));
abort();
goto error_1;
}
if((err = ftdi_set_latency_timer(ftdic, 1)) != 0) {
fprintf(stderr, "ftdi_set_latency_timer: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
goto error_2;
}
if((err = ftdi_set_baudrate(ftdic, 1000000)) != 0) {
fprintf(stderr, "ftdi_set_baudrate: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
goto error_2;
}
if((err = ftdi_write_data_set_chunksize(ftdic, BUF_SIZE)) != 0) {
fprintf(stderr, "ftdi_write_data_set_chunksize: %d: %s\n",
err, ftdi_get_error_string(ftdic));
abort();
goto error_2;
}
assert(gdb_if_init() == 0);
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
ret = cl_execute(&cl_opts);
} else {
assert(gdb_if_init() == 0);
return;
}
error_2:
ftdi_usb_close(ftdic);
error_1:
ftdi_free(ftdic);
exit(ret);
}
void platform_srst_set_val(bool assert)

View File

@ -1,7 +1,7 @@
TARGET=blackmagic_stlinkv2
SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DSTLINKV2 -DJTAG_HL -DENABLE_DEBUG
CFLAGS +=-I ./target
CFLAGS +=-I ./target -I./platforms/pc
LDFLAGS += -lusb-1.0
ifneq (, $(findstring mingw, $(SYS)))
LDFLAGS += -lws2_32
@ -9,5 +9,5 @@ else ifneq (, $(findstring cygwin, $(SYS)))
LDFLAGS += -lws2_32
endif
VPATH += platforms/pc
SRC += timing.c stlinkv2.c
SRC += timing.c stlinkv2.c cl_utils.c
OWN_HL = 1

View File

@ -36,6 +36,8 @@
#include <ctype.h>
#include <sys/time.h>
#include "cl_utils.h"
#if !defined(timersub)
/* This is a copy from GNU C Library (GNU LGPL 2.1), sys/time.h. */
# define timersub(a, b, result) \
@ -219,6 +221,7 @@ typedef struct {
uint8_t ver_swim;
uint8_t ver_bridge;
uint16_t block_size;
bool ap_error;
libusb_device_handle *handle;
struct libusb_transfer* req_trans;
struct libusb_transfer* rep_trans;
@ -397,7 +400,7 @@ static int send_recv(uint8_t *txbuf, size_t txsize,
if (res >0) {
int i;
uint8_t *p = rxbuf;
DEBUG_USB(" Rec (%" PRI_SIZET "/%d)", rxsize, res);
DEBUG_USB(" Rec (%zu/%d)", rxsize, res);
for (i = 0; i < res && i < 32 ; i++) {
if ( i && ((i & 7) == 0))
DEBUG_USB(".");
@ -464,6 +467,7 @@ static int stlink_usb_error_check(uint8_t *data, bool verbose)
* Change in error status when reading outside RAM.
* This fix allows CDT plugin to visualize memory.
*/
Stlink.ap_error = true;
if (verbose)
DEBUG("STLINK_SWD_AP_FAULT\n");
return STLINK_ERROR_DP_FAULT;
@ -685,46 +689,18 @@ static void stlink_resetsys(void)
send_recv(cmd, 16, data, 2);
}
void stlink_help(char **argv)
{
DEBUG("Blackmagic Debug Probe on STM StlinkV2 and 3\n\n");
DEBUG("Usage: %s [options]\n", argv[0]);
DEBUG("\t-v[1|2]\t\t: Increasing verbosity\n");
DEBUG("\t-s \"string\"\t: Use Stlink with (partial) "
"serial number \"string\"\n");
DEBUG("\t-n\t\t: Exit immediate if no device found\n");
DEBUG("\t-h\t\t: This help.\n");
exit(0);
}
void stlink_init(int argc, char **argv)
{
BMP_CL_OPTIONS_t cl_opts = {0};
cl_opts.opt_idstring = "Blackmagic Debug Probe on StlinkV2/3";
cl_init(&cl_opts, argc, argv);
libusb_device **devs, *dev;
int r;
int ret = -1;
atexit(exit_function);
signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler);
libusb_init(&Stlink.libusb_ctx);
char *serial = NULL;
int c;
bool wait_for_attach = true;
while((c = getopt(argc, argv, "ns:v:h")) != -1) {
switch(c) {
case 'n':
wait_for_attach = false;
break;
case 's':
serial = optarg;
break;
case 'v':
if (optarg)
debug_level = atoi(optarg);
break;
case 'h':
stlink_help(argv);
break;
}
}
r = libusb_init(NULL);
if (r < 0)
DEBUG("Failed: %s", libusb_strerror(r));
@ -792,7 +768,8 @@ void stlink_init(int argc, char **argv)
else
snprintf(s, 3, "%02x", *p & 0xff);
}
if (serial && (!strncmp(Stlink.serial, serial, strlen(serial))))
if (cl_opts.opt_serial && (!strncmp(Stlink.serial, cl_opts.opt_serial,
strlen(cl_opts.opt_serial))))
DEBUG("Found ");
if (desc.idProduct == PRODUCT_ID_STLINKV2) {
DEBUG("STLINKV20 serial %s\n", Stlink.serial);
@ -818,8 +795,9 @@ void stlink_init(int argc, char **argv)
DEBUG("Unknown STLINK variant, serial %s\n", Stlink.serial);
}
nr_stlinks++;
if (serial) {
if (!strncmp(Stlink.serial, serial, strlen(serial))) {
if (cl_opts.opt_serial) {
if (!strncmp(Stlink.serial, cl_opts.opt_serial,
strlen(cl_opts.opt_serial))) {
break;
} else {
libusb_close(Stlink.handle);
@ -833,15 +811,15 @@ void stlink_init(int argc, char **argv)
}
libusb_free_device_list(devs, 1);
if (!Stlink.handle) {
if (nr_stlinks && serial) {
DEBUG("No Stlink with given serial number %s\n", serial);
if (nr_stlinks && cl_opts.opt_serial) {
DEBUG("No Stlink with given serial number %s\n", cl_opts.opt_serial);
} else if (nr_stlinks > 1) {
DEBUG("Multiple Stlinks. Please specify serial number\n");
goto error;
} else {
DEBUG("No Stlink device found!\n");
}
if (hotplug && wait_for_attach) {
if (hotplug && !cl_opts.opt_no_wait) {
libusb_hotplug_callback_handle hp;
int rc = libusb_hotplug_register_callback
(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0,
@ -853,9 +831,9 @@ void stlink_init(int argc, char **argv)
goto error;
}
DEBUG("Waiting for %sST device%s%s to attach\n",
(serial)? "" : "some ",
(serial)? " with serial ": "",
(serial)? serial: "");
(cl_opts.opt_serial)? "" : "some ",
(cl_opts.opt_serial)? " with serial ": "",
(cl_opts.opt_serial)? cl_opts.opt_serial: "");
DEBUG("Terminate with ^C\n");
while (has_attached == 0) {
rc = libusb_handle_events (NULL);
@ -923,13 +901,17 @@ void stlink_init(int argc, char **argv)
}
stlink_leave_state();
stlink_resetsys();
assert(gdb_if_init() == 0);
return;
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
ret = cl_execute(&cl_opts);
} else {
assert(gdb_if_init() == 0);
return;
}
error_1:
libusb_close(Stlink.handle);
error:
libusb_exit(Stlink.libusb_ctx);
exit(-1);
exit(ret);
}
void stlink_srst_set_val(bool assert)
@ -1080,6 +1062,8 @@ uint32_t stlink_dp_error(ADIv5_DP_t *dp)
dp->fault = 0;
if (err)
DEBUG("stlink_dp_error %d\n", err);
err |= Stlink.ap_error;
Stlink.ap_error = false;
return err;
}
@ -1229,7 +1213,7 @@ void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
type = STLINK_DEBUG_READMEM_32BIT;
}
DEBUG_STLINK("%s len %" PRI_SIZET " addr 0x%08" PRIx32 " AP %d : ",
DEBUG_STLINK("%s len %zu addr 0x%08" PRIx32 " AP %d : ",
CMD, len, src, ap->apsel);
uint8_t cmd[16] = {
STLINK_DEBUG_COMMAND,
@ -1259,7 +1243,7 @@ void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len,
uint8_t *buffer)
{
DEBUG_STLINK("Mem Write8 AP %d len %" PRI_SIZET " addr 0x%08" PRIx32 ": ",
DEBUG_STLINK("Mem Write8 AP %d len %zu addr 0x%08" PRIx32 ": ",
ap->apsel, len, addr);
for (size_t t = 0; t < len; t++) {
DEBUG_STLINK("%02x", buffer[t]);
@ -1288,7 +1272,7 @@ void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len,
void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len,
uint16_t *buffer)
{
DEBUG_STLINK("Mem Write16 AP %d len %" PRI_SIZET " addr 0x%08" PRIx32 ": ",
DEBUG_STLINK("Mem Write16 AP %d len %zu addr 0x%08" PRIx32 ": ",
ap->apsel, len, addr);
for (size_t t = 0; t < len; t+=2) {
DEBUG_STLINK("%04x", buffer[t]);
@ -1308,7 +1292,7 @@ void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len,
void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len,
uint32_t *buffer)
{
DEBUG_STLINK("Mem Write32 AP %d len %" PRI_SIZET " addr 0x%08" PRIx32 ": ",
DEBUG_STLINK("Mem Write32 AP %d len %zu addr 0x%08" PRIx32 ": ",
ap->apsel, len, addr);
for (size_t t = 0; t < len; t+=4) {
DEBUG_STLINK("%04x", buffer[t]);

355
src/platforms/pc/cl_utils.c Normal file
View File

@ -0,0 +1,355 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2019
* Written by 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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/>.
*/
/* This file allows pc-hosted BMP platforms to erase and flash a
* binary file from the command line.
*/
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "cl_utils.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#else
# include <sys/mman.h>
#endif
struct mmap_data {
void *data;
size_t size;
#if defined(_WIN32) || defined(__CYGWIN__)
HANDLE hFile;
HANDLE hMapFile;
#else
int fd;
#endif
};
static int bmp_mmap(char *file, struct mmap_data *map)
{
#if defined(_WIN32) || defined(__CYGWIN__)
map->hFile = CreateFile(file, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, 0, NULL);
if (map->hFile == INVALID_HANDLE_VALUE) {
DEBUG("Open file %s failed: %s\n", file, strerror(errno));
return -1;
}
map->size = GetFileSize(map->hFile, NULL);
map->hMapFile = CreateFileMapping(
map->hFile,
NULL, /* default security */
PAGE_READONLY , /* read only access */
0, /* max. object size high */
0, /* max. object size low */
NULL); /* name of mapping object */
if (map->hMapFile == NULL || map->hMapFile == INVALID_HANDLE_VALUE) {
DEBUG("Map file %s failed: %s\n", file, strerror(errno));
CloseHandle(map->hFile);
return -1;
}
map->data = MapViewOfFile(map->hMapFile, FILE_MAP_READ, 0, 0, 0);
if (!map->data) {
printf("Could not create file mapping object (%s).\n",
strerror(errno));
CloseHandle(map->hMapFile);
return -1;
}
#else
map->fd = open(file, O_RDONLY | O_BINARY);
if (map->fd < 0) {
DEBUG("Open file %s failed: %s\n", file, strerror(errno));
return -1;
}
struct stat stat;
if (fstat(map->fd, &stat))
return -1;
map->size = stat.st_size;
map->data = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, map->fd, 0);
#endif
return 0;
}
static void bmp_munmap(struct mmap_data *map)
{
#if defined(_WIN32) || defined(__CYGWIN__)
UnmapViewOfFile(map->data);
CloseHandle(map->hMapFile);
CloseHandle(map->hFile);
#else
munmap(map->data, map->size);
#endif
}
static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
{
printf("%s\n\n", opt->opt_idstring);
printf("Usage: %s [options]\n", argv[0]);
printf("\t-h\t\t: This help.\n");
printf("\t-v[1|2]\t\t: Increasing verbosity\n");
printf("\t-s \"string\"\t: Use dongle with (partial) "
"serial number \"string\"\n");
printf("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n");
printf("\t-n\t\t: Exit immediate if no device found\n");
printf("\tRun mode related options:\n");
printf("\t-t\t\t: Scan SWD, with no target found scan jtag and exit\n");
printf("\t-V\t\t: Verify flash against binary file\n");
printf("\t-r\t\t: Read flash and write to binary file\n");
printf("\t\tDefault mode is starting the debug server\n");
printf("\tFlash operation modifiers options:\n");
printf("\t-a <num>\t: Start flash operation at flash address <num>\n"
"\t\t\tDefault start is 0x08000000\n");
printf("\t-S <num>\t: Read <num> bytes. Default is until read fails.\n");
printf("\t-j\t\t: Use JTAG. SWD is default.\n");
printf("\t <file>\t\t: Use (binary) file <file> for flash operation\n"
"\t\t\tGiven <file> writes to flash if neither -r or -V is given\n");
exit(0);
}
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
{
int c;
opt->opt_target_dev = 1;
opt->opt_flash_start = 0x08000000;
opt->opt_flash_size = 16 * 1024 *1024;
while((c = getopt(argc, argv, "hv::s:c:nN:tVta:S:jr")) != -1) {
switch(c) {
case 'c':
if (optarg)
opt->opt_cable = optarg;
break;
case 'h':
cl_help(argv, opt);
break;
case 'v':
if (optarg)
opt->opt_debuglevel = strtol(optarg, NULL, 0);
break;
case 'j':
opt->opt_usejtag = true;
break;
case 'n':
opt->opt_no_wait = true;
break;
case 's':
if (optarg)
opt->opt_serial = optarg;
break;
case 't':
opt->opt_mode = BMP_MODE_TEST;
break;
case 'V':
opt->opt_mode = BMP_MODE_FLASH_VERIFY;
break;
case 'r':
opt->opt_mode = BMP_MODE_FLASH_READ;
break;
case 'a':
if (optarg)
opt->opt_flash_start = strtol(optarg, NULL, 0);
break;
case 'N':
if (optarg)
opt->opt_target_dev = strtol(optarg, NULL, 0);
break;
case 'S':
if (optarg) {
char *endptr;
opt->opt_flash_size = strtol(optarg, &endptr, 0);
if (endptr) {
switch(endptr[0]) {
case 'k':
case 'K':
opt->opt_flash_size *= 1024;
break;
case 'm':
case 'M':
opt->opt_flash_size *= 1024 * 1024;
break;
}
}
}
}
}
if ((optind) && argv[optind]) {
if (opt->opt_mode == BMP_MODE_DEBUG)
opt->opt_mode = BMP_MODE_FLASH_WRITE;
opt->opt_flash_file = argv[optind];
}
/* Checks */
if ((opt->opt_flash_file) && (opt->opt_mode == BMP_MODE_TEST)) {
printf("Ignoring filename in test mode\n");
opt->opt_flash_file = NULL;
}
}
int cl_execute(BMP_CL_OPTIONS_t *opt)
{
int res = -1;
int num_targets;
if (opt->opt_mode == BMP_MODE_TEST) {
printf("Running in Test Mode\n");
num_targets = adiv5_swdp_scan();
if (num_targets == 0)
num_targets = jtag_scan(NULL);
if (num_targets)
return 0;
else
return res;
}
if (opt->opt_usejtag) {
num_targets = jtag_scan(NULL);
} else {
num_targets = adiv5_swdp_scan();
}
if (!num_targets) {
DEBUG("No target found\n");
return res;
}
if (opt->opt_target_dev > num_targets) {
DEBUG("Given target nummer %d not available\n", opt->opt_target_dev);
return res;
}
struct target_controller tc = {NULL};
target *t = target_attach_n(opt->opt_target_dev, &tc);
if (!t) {
DEBUG("Can not attach to target %d\n", opt->opt_target_dev);
goto target_detach;
}
int read_file = -1;
struct mmap_data map = {0};
if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
(opt->opt_mode == BMP_MODE_FLASH_VERIFY)) {
int mmap_res = bmp_mmap(opt->opt_flash_file, &map);
if (mmap_res) {
DEBUG("Can not map file: %s. Aborting!\n", strerror(errno));
goto target_detach;
}
} else {
/* Open as binary */
read_file = open(opt->opt_flash_file, O_CREAT | O_RDWR | O_BINARY,
S_IRUSR | S_IWUSR);
if (read_file == -1) {
printf("Error opening flashfile %s for read: %s\n",
opt->opt_flash_file, strerror(errno));
return res;
}
}
if (opt->opt_flash_size < map.size)
/* restrict to size given on command line */
map.size = opt->opt_flash_size;
if (opt->opt_mode == BMP_MODE_FLASH_WRITE) {
DEBUG("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
opt->opt_flash_start);
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
map.size);
if (erased) {
DEBUG("Erased failed!\n");
goto free_map;
} else {
DEBUG("Flashing %zu bytes at 0x%08" PRIx32 "\n",
map.size, opt->opt_flash_start);
unsigned int flashed = target_flash_write(t, opt->opt_flash_start,
map.data, map.size);
/* Buffered write cares for padding*/
if (flashed) {
DEBUG("Flashing failed!\n");
} else {
DEBUG("Success!\n");
res = 0;
}
}
target_flash_done(t);
} else {
#define WORKSIZE 1024
uint8_t *data = malloc(WORKSIZE);
if (!data) {
printf("Can not malloc memory for flash read/verify operation\n");
return res;
}
if (opt->opt_mode == BMP_MODE_FLASH_READ)
printf("Reading flash from 0x%08" PRIx32 " for %zu"
" bytes to %s\n", opt->opt_flash_start, opt->opt_flash_size,
opt->opt_flash_file);
uint32_t flash_src = opt->opt_flash_start;
size_t size = opt->opt_flash_size;
int bytes_read = 0;
void *flash = map.data;
while (size) {
int worksize = (size > WORKSIZE) ? WORKSIZE : size;
int n_read = target_mem_read(t, data, flash_src, worksize);
if (n_read) {
if (opt->opt_flash_size == 0) {/* we reached end of flash */
printf("Reached end of flash at size %" PRId32 "\n",
flash_src - opt->opt_flash_start);
break;
} else {
printf("Read failed at flash address 0x%08" PRIx32 "\n",
flash_src);
break;
}
} else {
bytes_read += worksize;
}
if (opt->opt_mode == BMP_MODE_FLASH_VERIFY) {
int difference = memcmp(data, flash, worksize);
if (difference){
printf("Verify failed at flash region 0x%08" PRIx32 "\n",
flash_src);
return -1;
}
flash += worksize;
} else if (read_file != -1) {
int written = write(read_file, data, worksize);
if (written < worksize) {
printf("Read failed at flash region 0x%08" PRIx32 "\n",
flash_src);
return -1;
}
}
flash_src += worksize;
size -= worksize;
if (size <= 0)
res = 0;
}
if (read_file != -1)
close(read_file);
printf("Read/Verifed succeeded for %d bytes\n", bytes_read);
}
target_reset(t);
free_map:
if (map.size)
bmp_munmap(&map);
target_detach:
if (t)
target_detach(t);
return res;
}

View File

@ -0,0 +1,51 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2019 Uwe Bonnes
* Written by 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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/>.
*/
/* This file implements the interface to command line command for PC-Hosted
* platforms.
*/
#if !defined(__CL_UTILS_H)
#define __CL_UTILS_H
enum bmp_cl_mode {
BMP_MODE_DEBUG,
BMP_MODE_TEST,
BMP_MODE_FLASH_WRITE,
BMP_MODE_FLASH_READ,
BMP_MODE_FLASH_VERIFY
};
typedef struct BMP_CL_OPTIONS_s {
enum bmp_cl_mode opt_mode;
bool opt_usejtag;
bool opt_no_wait;
char *opt_flash_file;
char *opt_serial;
char *opt_cable;
int opt_debuglevel;
int opt_target_dev;
uint32_t opt_flash_start;
size_t opt_flash_size;
char *opt_idstring;
}BMP_CL_OPTIONS_t;
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv);
int cl_execute(BMP_CL_OPTIONS_t *opt);
#endif

766
src/target/#samd.c# Normal file
View File

@ -0,0 +1,766 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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/>.
*/
/* This file implements Atmel SAM D target specific functions for
* detecting the device, providing the XML memory map and Flash memory
* programming.
*
* Tested with
* * SAMD20E17A (rev C)
* * SAMD20J18A (rev B)
* * SAMD21J18A (rev B)
* *
*/
/* Refer to the SAM D20 Datasheet:
* http://www.atmel.com/Images/Atmel-42129-SAM-D20_Datasheet.pdf
* particularly Sections 12. DSU and 20. NVMCTRL
*/
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
static int samd_flash_erase(struct target_flash *t, target_addr addr, size_t len);
static int samd_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
bool samd_cmd_erase_all(target *t, int argc, const char **argv);
static bool samd_cmd_lock_flash(target *t, int argc, const char **argv);
static bool samd_cmd_unlock_flash(target *t, int argc, const char **argv);
static bool samd_cmd_unlock_bootprot(target *t, int argc, const char **argv);
static bool samd_cmd_lock_bootprot(target *t, int argc, const char **argv);
static bool samd_cmd_read_userrow(target *t, int argc, const char **argv);
static bool samd_cmd_serial(target *t, int argc, const char **argv);
static bool samd_cmd_mbist(target *t, int argc, const char **argv);
static bool samd_cmd_ssb(target *t, int argc, const char **argv);
const struct command_s samd_cmd_list[] = {
{"erase_mass", (cmd_handler)samd_cmd_erase_all, "Erase entire flash memory"},
{"lock_flash", (cmd_handler)samd_cmd_lock_flash, "Locks flash against spurious commands"},
{"unlock_flash", (cmd_handler)samd_cmd_unlock_flash, "Unlocks flash"},
{"lock_bootprot", (cmd_handler)samd_cmd_lock_bootprot, "Lock the boot protections to maximum"},
{"unlock_bootprot", (cmd_handler)samd_cmd_unlock_bootprot, "Unlock the boot protections to minimum"},
{"user_row", (cmd_handler)samd_cmd_read_userrow, "Prints user row from flash"},
{"serial", (cmd_handler)samd_cmd_serial, "Prints serial number"},
{"mbist", (cmd_handler)samd_cmd_mbist, "Runs the built-in memory test"},
{"set_security_bit", (cmd_handler)samd_cmd_ssb, "Sets the Security Bit"},
{NULL, NULL, NULL}
};
/* Non-Volatile Memory Controller (NVMC) Parameters */
#define SAMD_ROW_SIZE 256
#define SAMD_PAGE_SIZE 64
/* -------------------------------------------------------------------------- */
/* Non-Volatile Memory Controller (NVMC) Registers */
/* -------------------------------------------------------------------------- */
#define SAMD_NVMC 0x41004000
#define SAMD_NVMC_CTRLA (SAMD_NVMC + 0x0)
#define SAMD_NVMC_CTRLB (SAMD_NVMC + 0x04)
#define SAMD_NVMC_PARAM (SAMD_NVMC + 0x08)
#define SAMD_NVMC_INTFLAG (SAMD_NVMC + 0x14)
#define SAMD_NVMC_ADDRESS (SAMD_NVMC + 0x1C)
/* Control A Register (CTRLA) */
#define SAMD_CTRLA_CMD_KEY 0xA500
#define SAMD_CTRLA_CMD_ERASEROW 0x0002
#define SAMD_CTRLA_CMD_WRITEPAGE 0x0004
#define SAMD_CTRLA_CMD_ERASEAUXROW 0x0005
#define SAMD_CTRLA_CMD_WRITEAUXPAGE 0x0006
#define SAMD_CTRLA_CMD_LOCK 0x0040
#define SAMD_CTRLA_CMD_UNLOCK 0x0041
#define SAMD_CTRLA_CMD_PAGEBUFFERCLEAR 0x0044
#define SAMD_CTRLA_CMD_SSB 0x0045
#define SAMD_CTRLA_CMD_INVALL 0x0046
/* Interrupt Flag Register (INTFLAG) */
#define SAMD_NVMC_READY (1 << 0)
/* Non-Volatile Memory Calibration and Auxiliary Registers */
#define SAMD_NVM_USER_ROW_LOW 0x00804000
#define SAMD_NVM_USER_ROW_HIGH 0x00804004
#define SAMD_NVM_CALIBRATION 0x00806020
#define SAMD_NVM_SERIAL(n) (0x0080A00C + (0x30 * ((n + 3) / 4)) + \
(0x4 * n))
/* -------------------------------------------------------------------------- */
/* Device Service Unit (DSU) Registers */
/* -------------------------------------------------------------------------- */
#define SAMD_DSU 0x41002000
#define SAMD_DSU_EXT_ACCESS (SAMD_DSU + 0x100)
#define SAMD_DSU_CTRLSTAT (SAMD_DSU_EXT_ACCESS + 0x0)
#define SAMD_DSU_ADDRESS (SAMD_DSU_EXT_ACCESS + 0x4)
#define SAMD_DSU_LENGTH (SAMD_DSU_EXT_ACCESS + 0x8)
#define SAMD_DSU_DID (SAMD_DSU_EXT_ACCESS + 0x018)
#define SAMD_DSU_PID(n) (SAMD_DSU + 0x1FE0 + \
(0x4 * (n % 4)) - (0x10 * (n / 4)))
#define SAMD_DSU_CID(n) (SAMD_DSU + 0x1FF0 + \
(0x4 * (n % 4)))
/* Control and Status Register (CTRLSTAT) */
#define SAMD_CTRL_CHIP_ERASE (1 << 4)
#define SAMD_CTRL_MBIST (1 << 3)
#define SAMD_CTRL_CRC (1 << 2)
#define SAMD_STATUSA_PERR (1 << 12)
#define SAMD_STATUSA_FAIL (1 << 11)
#define SAMD_STATUSA_BERR (1 << 10)
#define SAMD_STATUSA_CRSTEXT (1 << 9)
#define SAMD_STATUSA_DONE (1 << 8)
#define SAMD_STATUSB_PROT (1 << 16)
/* Device Identification Register (DID) */
#define SAMD_DID_MASK 0xFFBC0000
#define SAMD_DID_CONST_VALUE 0x10000000
#define SAMD_DID_DEVSEL_MASK 0x0F
#define SAMD_DID_DEVSEL_POS 0
#define SAMD_DID_REVISION_MASK 0x0F
#define SAMD_DID_REVISION_POS 8
#define SAMD_DID_SERIES_MASK 0x03
#define SAMD_DID_SERIES_POS 16
/* Peripheral ID */
#define SAMD_PID_MASK 0x00F7FFFF
#define SAMD_PID_CONST_VALUE 0x0001FCD0
/* Component ID */
#define SAMD_CID_VALUE 0xB105100D
/**
* Reads the SAM D20 Peripheral ID
*/
uint64_t samd_read_pid(target *t)
{
uint64_t pid = 0;
uint8_t i, j;
/* Five PID registers to read LSB first */
for (i = 0, j = 0; i < 5; i++, j += 8)
pid |= (target_mem_read32(t, SAMD_DSU_PID(i)) & 0xFF) << j;
return pid;
}
/**
* Reads the SAM D20 Component ID
*/
uint32_t samd_read_cid(target *t)
{
uint64_t cid = 0;
uint8_t i, j;
/* Four CID registers to read LSB first */
for (i = 0, j = 0; i < 4; i++, j += 8)
cid |= (target_mem_read32(t, SAMD_DSU_CID(i)) & 0xFF) << j;
return cid;
}
/**
* Overloads the default cortexm reset function with a version that
* removes the target from extended reset where required.
*/
void samd_reset(target *t)
{
/**
* SRST is not asserted here as it appears to reset the adiv5
* logic, meaning that subsequent adiv5_* calls PLATFORM_FATAL_ERROR.
*
* This is ok as normally you can just connect the debugger and go,
* but if that's not possible (protection or SWCLK being used for
* something else) then having SWCLK low on reset should get you
* debug access (cold-plugging). TODO: Confirm this
*
* See the SAM D20 datasheet §12.6 Debug Operation for more
* details.
*
* jtagtap_srst(true);
* jtagtap_srst(false);
*/
/* Read DHCSR here to clear S_RESET_ST bit before reset */
target_mem_read32(t, CORTEXM_DHCSR);
/* Request system reset from NVIC: SRST doesn't work correctly */
/* This could be VECTRESET: 0x05FA0001 (reset only core)
* or SYSRESETREQ: 0x05FA0004 (system reset)
*/
target_mem_write32(t, CORTEXM_AIRCR,
CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ);
/* Exit extended reset */
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_CRSTEXT);
}
/* Poll for release from reset */
while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST);
/* Reset DFSR flags */
target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
/* Clear any target errors */
target_check_error(t);
}
/**
* Overloads the default cortexm detached function with a version that
* removes the target from extended reset where required.
*
* Only required for SAM D20 _Revision B_ Silicon
*/
static void
samd20_revB_detach(target *t)
{
cortexm_detach(t);
/* ---- Additional ---- */
/* Exit extended reset */
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
SAMD_STATUSA_CRSTEXT);
}
}
/**
* Overloads the default cortexm halt_resume function with a version
* that removes the target from extended reset where required.
*
* Only required for SAM D20 _Revision B_ Silicon
*/
static void
samd20_revB_halt_resume(target *t, bool step)
{
cortexm_halt_resume(t, step);
/* ---- Additional ---- */
/* Exit extended reset */
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) & SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
SAMD_STATUSA_CRSTEXT);
}
}
/**
* Overload the default cortexm attach for when the samd is protected.
*
* If the samd is protected then the default cortexm attach will
* fail as the S_HALT bit in the DHCSR will never go high. This
* function allows users to attach on a temporary basis so they can
* rescue the device.
*/
bool samd_protected_attach(target *t)
{
/**
* TODO: Notify the user that we're not really attached and
* they should issue the 'monitor erase_mass' command to
* regain access to the chip.
*/
/* Patch back in the normal cortexm attach for next time */
t->attach = cortexm_attach;
/* Allow attach this time */
return true;
}
/**
* Use the DSU Device Indentification Register to populate a struct
* describing the SAM D device.
*/
struct samd_descr {
uint8_t series;
char revision;
char pin;
uint8_t mem;
char package[3];
};
struct samd_descr samd_parse_device_id(uint32_t did)
{
struct samd_descr samd;
memset(samd.package, 0, 3);
uint8_t series = (did >> SAMD_DID_SERIES_POS)
& SAMD_DID_SERIES_MASK;
uint8_t revision = (did >> SAMD_DID_REVISION_POS)
& SAMD_DID_REVISION_MASK;
uint8_t devsel = (did >> SAMD_DID_DEVSEL_POS)
& SAMD_DID_DEVSEL_MASK;
/* Series */
switch (series) {
case 0: samd.series = 20; break;
case 1: samd.series = 21; break;
case 2: samd.series = 10; break;
case 3: samd.series = 11; break;
}
/* Revision */
samd.revision = 'A' + revision;
switch (samd.series) {
case 20: /* SAM D20 */
case 21: /* SAM D21 */
switch (devsel / 5) {
case 0: samd.pin = 'J'; break;
case 1: samd.pin = 'G'; break;
case 2: samd.pin = 'E'; break;
default: samd.pin = 'u'; break;
}
samd.mem = 18 - (devsel % 5);
break;
case 10: /* SAM D10 */
case 11: /* SAM D11 */
switch (devsel / 3) {
case 0: samd.package[0] = 'M'; break;
case 1: samd.package[0] = 'S'; samd.package[1] = 'S'; break;
}
samd.pin = 'D';
samd.mem = 14 - (devsel % 3);
break;
}
return samd;
}
static void samd_add_flash(target *t, uint32_t addr, size_t length)
{
struct target_flash *f = calloc(1, sizeof(*f));
if (!f) { /* calloc failed: heap exhaustion */
DEBUG("calloc: failed in %s\n", __func__);
return;
}
f->start = addr;
f->length = length;
f->blocksize = SAMD_ROW_SIZE;
f->erase = samd_flash_erase;
f->write = samd_flash_write;
f->buf_size = SAMD_PAGE_SIZE;
target_add_flash(t, f);
}
char variant_string[60];
bool samd_probe(target *t)
{
uint32_t cid = samd_read_cid(t);
uint32_t pid = samd_read_pid(t);
/* Check the ARM Coresight Component and Perhiperal IDs */
if ((cid != SAMD_CID_VALUE) ||
((pid & SAMD_PID_MASK) != SAMD_PID_CONST_VALUE))
return false;
/* Read the Device ID */
uint32_t did = target_mem_read32(t, SAMD_DSU_DID);
/* If the Device ID matches */
if ((did & SAMD_DID_MASK) != SAMD_DID_CONST_VALUE)
return false;
uint32_t ctrlstat = target_mem_read32(t, SAMD_DSU_CTRLSTAT);
struct samd_descr samd = samd_parse_device_id(did);
/* Protected? */
bool protected = (ctrlstat & SAMD_STATUSB_PROT);
/* Part String */
if (protected) {
snprintf(variant_string, sizeof(variant_string),
"Atmel SAMD%d%c%dA%s (rev %c) (PROT=1)",
samd.series, samd.pin, samd.mem,
samd.package, samd.revision);
} else {
snprintf(variant_string, sizeof(variant_string),
"Atmel SAMD%d%c%dA%s (rev %c)",
samd.series, samd.pin, samd.mem,
samd.package, samd.revision);
}
/* Setup Target */
t->driver = variant_string;
t->reset = samd_reset;
if (samd.series == 20 && samd.revision == 'B') {
/**
* These functions check for and
* extended reset. Appears to be
* related to Errata 35.4.1 ref 12015
*/
t->detach = samd20_revB_detach;
t->halt_resume = samd20_revB_halt_resume;
}
if (protected) {
/**
* Overload the default cortexm attach
* for when the samd is protected.
* This function allows users to
* attach on a temporary basis so they
* can rescue the device.
*/
t->attach = samd_protected_attach;
}
target_add_ram(t, 0x20000000, 0x8000);
samd_add_flash(t, 0x00000000, 0x40000);
target_add_commands(t, samd_cmd_list, "SAMD");
/* If we're not in reset here */
if (!platform_srst_get_val()) {
/* We'll have to release the target from
* extended reset to make attach possible */
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
SAMD_STATUSA_CRSTEXT) {
/* Write bit to clear from extended reset */
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
SAMD_STATUSA_CRSTEXT);
}
}
return true;
}
/**
* Temporary (until next reset) flash memory locking / unlocking
*/
static void samd_lock_current_address(target *t)
{
/* Issue the unlock command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_LOCK);
}
static void samd_unlock_current_address(target *t)
{
/* Issue the unlock command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_UNLOCK);
}
/**
* Erase flash row by row
*/
static int samd_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
while (len) {
/* Write address of first word in row to erase it */
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
target_mem_write32(t, SAMD_NVMC_ADDRESS, addr >> 1);
/* Unlock */
samd_unlock_current_address(t);
/* Issue the erase command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEROW);
/* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t))
return -1;
/* Lock */
samd_lock_current_address(t);
addr += f->blocksize;
len -= f->blocksize;
}
return 0;
}
/**
* Write flash page by page
*/
static int samd_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
{
target *t = f->t;
/* Write within a single page. This may be part or all of the page */
target_mem_write(t, dest, src, len);
/* Unlock */
samd_unlock_current_address(t);
/* Issue the write page command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE);
/* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t))
return -1;
/* Lock */
samd_lock_current_address(t);
return 0;
}
/**
* Uses the Device Service Unit to erase the entire flash
*/
bool samd_cmd_erase_all(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
/* Clear the DSU status bits */
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
SAMD_STATUSA_DONE | SAMD_STATUSA_PERR |
SAMD_STATUSA_FAIL);
/* Erase all */
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_CHIP_ERASE);
/* Poll for DSU Ready */
uint32_t status;
while (((status = target_mem_read32(t, SAMD_DSU_CTRLSTAT)) &
(SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0)
if (target_check_error(t))
return false;
/* Test the protection error bit in Status A */
if (status & SAMD_STATUSA_PERR) {
tc_printf(t, "Erase failed due to a protection error.\n");
return true;
}
/* Test the fail bit in Status A */
if (status & SAMD_STATUSA_FAIL) {
tc_printf(t, "Erase failed.\n");
return true;
}
tc_printf(t, "Erase successful!\n");
return true;
}
/**
* Sets the NVM region lock bits in the User Row. This value is read
* at startup as the default value for the lock bits, and hence does
* not take effect until a reset.
*
* 0x0000 = Lock, 0xFFFF = Unlock (default)
*/
static bool samd_set_flashlock(target *t, uint16_t value, const char **argv)
{
(void)argv;
uint32_t high = target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH);
uint32_t low = target_mem_read32(t, SAMD_NVM_USER_ROW_LOW);
/* Write address of a word in the row to erase it */
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
target_mem_write32(t, SAMD_NVMC_ADDRESS, SAMD_NVM_USER_ROW_LOW >> 1);
/* Issue the erase command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEAUXROW);
/* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t))
return -1;
/* Modify the high byte of the user row */
high = (high & 0x0000FFFF) | ((value << 16) & 0xFFFF0000);
/* Write back */
target_mem_write32(t, SAMD_NVM_USER_ROW_LOW, low);
target_mem_write32(t, SAMD_NVM_USER_ROW_HIGH, high);
/* Issue the page write command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEAUXPAGE);
return true;
}
static bool samd_cmd_lock_flash(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
return samd_set_flashlock(t, 0x0000, NULL);
}
static bool samd_cmd_unlock_flash(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
return samd_set_flashlock(t, 0xFFFF, NULL);
}
static bool samd_set_bootprot(target *t, uint16_t value, const char **argv)
{
(void)argv;
uint32_t high = target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH);
uint32_t low = target_mem_read32(t, SAMD_NVM_USER_ROW_LOW);
/* Write address of a word in the row to erase it */
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
target_mem_write32(t, SAMD_NVMC_ADDRESS, SAMD_NVM_USER_ROW_LOW >> 1);
/* Issue the erase command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEAUXROW);
/* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t))
return -1;
/* Modify the low word of the user row */
low = (low & 0xFFFFFFF8) | ((value << 0 ) & 0x00000007);
/* Write back */
target_mem_write32(t, SAMD_NVM_USER_ROW_LOW, low);
target_mem_write32(t, SAMD_NVM_USER_ROW_HIGH, high);
/* Issue the page write command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEAUXPAGE);
return true;
}
static bool samd_cmd_lock_bootprot(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
return samd_set_bootprot(t, 0, NULL);
}
static bool samd_cmd_unlock_bootprot(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
return samd_set_bootprot(t, 7, NULL);
}
static bool samd_cmd_read_userrow(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
tc_printf(t, "User Row: 0x%08x%08x\n",
target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH),
target_mem_read32(t, SAMD_NVM_USER_ROW_LOW));
return true;
}
/**
* Reads the 128-bit serial number from the NVM
*/
static bool samd_cmd_serial(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
tc_printf(t, "Serial Number: 0x");
for (uint32_t i = 0; i < 4; i++) {
tc_printf(t, "%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i)));
}
tc_printf(t, "\n");
return true;
}
/**
* Returns the size (in bytes) of the current SAM D20's flash memory.
*/
static uint32_t samd_flash_size(target *t)
{
/* Read the Device ID */
uint32_t did = target_mem_read32(t, SAMD_DSU_DID);
/* Mask off the device select bits */
uint8_t devsel = did & SAMD_DID_DEVSEL_MASK;
/* Shift the maximum flash size (256KB) down as appropriate */
return (0x40000 >> (devsel % 5));
}
/**
* Runs the Memory Built In Self Test (MBIST)
*/
static bool samd_cmd_mbist(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
/* Write the memory parameters to the DSU */
target_mem_write32(t, SAMD_DSU_ADDRESS, 0);
target_mem_write32(t, SAMD_DSU_LENGTH, samd_flash_size(t));
/* Clear the fail bit */
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_FAIL);
/* Write the MBIST command */
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_MBIST);
/* Poll for DSU Ready */
uint32_t status;
while (((status = target_mem_read32(t, SAMD_DSU_CTRLSTAT)) &
(SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0)
if (target_check_error(t))
return false;
/* Test the protection error bit in Status A */
if (status & SAMD_STATUSA_PERR) {
tc_printf(t, "MBIST not run due to protection error.\n");
return true;
}
/* Test the fail bit in Status A */
if (status & SAMD_STATUSA_FAIL) {
tc_printf(t, "MBIST Fail @ 0x%08x\n",
target_mem_read32(t, SAMD_DSU_ADDRESS));
} else {
tc_printf(t, "MBIST Passed!\n");
}
return true;
}
/**
* Sets the security bit
*/
static bool samd_cmd_ssb(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
/* Issue the ssb command */
target_mem_write32(t, SAMD_NVMC_CTRLA,
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_SSB);
/* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t))
return -1;
tc_printf(t, "Set the security bit! "
"You will need to issue 'monitor erase_mass' to clear this.\n");
return true;
}

2
src/target/.gdb_history Normal file
View File

@ -0,0 +1,2 @@
info mem
quit

View File

@ -489,11 +489,13 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
}
/* Probe for APs on this DP */
uint32_t last_base = 0;
for(int i = 0; i < 256; i++) {
int void_aps = 0;
for(int i = 0; (i < 256) && (void_aps < 8); i++) {
ADIv5_AP_t *ap = NULL;
if (adiv5_ap_setup(i))
ap = adiv5_new_ap(dp, i);
if (ap == NULL) {
void_aps++;
adiv5_ap_cleanup(i);
if (i == 0)
return;

View File

@ -686,7 +686,10 @@ static int efm32_flash_erase(struct target_flash *f, target_addr addr, size_t le
}
addr += f->blocksize;
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
}
return 0;
@ -829,7 +832,7 @@ static bool efm32_cmd_efm_info(target *t, int argc, const char **argv)
if (di_version == 2) {
efm32_v2_di_miscchip_t miscchip = efm32_v2_read_miscchip(t, di_version);
efm32_v2_di_pkgtype_t const* pkgtype;
efm32_v2_di_pkgtype_t const* pkgtype = NULL;
efm32_v2_di_tempgrade_t const* tempgrade;
for (size_t i = 0; i < (sizeof(efm32_v2_di_pkgtypes) /

View File

@ -310,7 +310,10 @@ static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t l
while (len) {
if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL)) {
/* Different targets have different flash erase sizes */
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
addr += f->blocksize;
} else {
return 1;
@ -345,7 +348,10 @@ static int kl_gen_flash_write(struct target_flash *f,
while (len) {
if (kl_gen_command(f->t, write_cmd, dest, src)) {
len -= kf->write_len;
if (len > kf->write_len)
len -= kf->write_len;
else
len = 0;
dest += kf->write_len;
src += kf->write_len;
} else {

View File

@ -119,8 +119,10 @@ int lmi_flash_erase(struct target_flash *f, target_addr addr, size_t len)
if (target_check_error(t))
return -1;
len -= BLOCK_SIZE;
if (len > BLOCK_SIZE)
len -= BLOCK_SIZE;
else
len = 0;
addr += BLOCK_SIZE;
}
return 0;

View File

@ -267,7 +267,10 @@ static int msp432_flash_erase(struct target_flash *f, target_addr addr, size_t l
/* update len and addr */
len -= f->blocksize;
addr += f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
}
return ret;
@ -295,7 +298,7 @@ static int msp432_flash_write(struct target_flash *f, target_addr dest,
regs[1] = dest; // Flash address to be write to in R1
regs[2] = len; // Size of buffer to be flashed in R2
DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08" PRI_SIZET "\n", dest, len);
DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08zu\n", dest, len);
/* Call ROM */
msp432_call_ROM(t, mf->FlashCtl_programMemory, regs);

View File

@ -180,7 +180,10 @@ static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t le
return -1;
addr += f->blocksize;
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
}
/* Return to read-only */

View File

@ -308,7 +308,10 @@ static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len
if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg))
return -1;
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
chunk += 8;
}
return 0;

View File

@ -393,7 +393,10 @@ sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len)
if (sam4l_flash_command(t, page, FLASH_CMD_EP)) {
return -1;
}
len -= SAM4L_PAGE_SIZE;
if (len > SAM4L_PAGE_SIZE)
len -= SAM4L_PAGE_SIZE;
else
len = 0;
addr += SAM4L_PAGE_SIZE;
}
return 0;

View File

@ -598,7 +598,10 @@ static int samd_flash_erase(struct target_flash *f, target_addr addr, size_t len
samd_lock_current_address(t);
addr += f->blocksize;
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
}
return 0;

View File

@ -210,8 +210,10 @@ static int stm32f1_flash_erase(struct target_flash *f,
DEBUG("stm32f1 flash erase: comm error\n");
return -1;
}
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
addr += f->blocksize;
}

View File

@ -411,7 +411,10 @@ static int stm32f4_flash_erase(struct target_flash *f, target_addr addr,
DEBUG("stm32f4 flash erase: comm error\n");
return -1;
}
len -= f->blocksize;
if (len > f->blocksize)
len -= f->blocksize;
else
len = 0;
sector++;
if ((sf->bank_split) && (sector == sf->bank_split))
sector = 16;

View File

@ -377,8 +377,10 @@ static int stm32lx_nvm_prog_erase(struct target_flash* f,
while (len > 0) {
/* Write first word of page to 0 */
target_mem_write32(t, addr, 0);
len -= page_size;
if (len > page_size)
len -= page_size;
else
len = 0;
addr += page_size;
}
@ -439,7 +441,6 @@ static int stm32lx_nvm_prog_write(struct target_flash *f,
return 0;
}
/** Erase a region of data flash using operations through the debug
interface . The flash is erased for all pages from addr to
addr+len, inclusive, on a word boundary. NVM register file
@ -471,7 +472,10 @@ static int stm32lx_nvm_data_erase(struct target_flash *f,
/* Write first word of page to 0 */
target_mem_write32(t, addr, 0);
len -= page_size;
if (len > page_size)
len -= page_size;
else
len = 0;
addr += page_size;
}

View File

@ -425,8 +425,10 @@ static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return -1;
len -= blocksize;
if (len > blocksize)
len -= blocksize;
else
len = 0;
addr += blocksize;
page++;
}