Browse Source

Infrastructure for command line interface to target

- Program, read and verify flash
- Test mode: Probe and attach to device and exit
pull/561/head
Uwe Bonnes 5 years ago
parent
commit
da5a0cd3f5
  1. 3
      src/platforms/libftdi/Makefile.inc
  2. 50
      src/platforms/libftdi/platform.c
  3. 4
      src/platforms/pc-stlinkv2/Makefile.inc
  4. 68
      src/platforms/pc-stlinkv2/stlinkv2.c
  5. 355
      src/platforms/pc/cl_utils.c
  6. 51
      src/platforms/pc/cl_utils.h

3
src/platforms/libftdi/Makefile.inc

@ -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

50
src/platforms/libftdi/platform.c

@ -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)
{
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;
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;
}
}
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;
}
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
ret = cl_execute(&cl_opts);
} else {
assert(gdb_if_init() == 0);
return;
}
assert(gdb_if_init() == 0);
error_2:
ftdi_usb_close(ftdic);
error_1:
ftdi_free(ftdic);
exit(ret);
}
void platform_srst_set_val(bool assert)

4
src/platforms/pc-stlinkv2/Makefile.inc

@ -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

68
src/platforms/pc-stlinkv2/stlinkv2.c

@ -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) \
@ -687,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));
@ -794,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);
@ -820,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);
@ -835,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,
@ -855,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);
@ -925,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)

355
src/platforms/pc/cl_utils.c

@ -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;
}

51
src/platforms/pc/cl_utils.h

@ -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
Loading…
Cancel
Save