Merge pull request #143 from gsmcmullin/work

Split target support from GDB server with clean interface.
This commit is contained in:
Gareth McMullin 2016-07-18 08:19:10 +12:00 committed by GitHub
commit de603f4bd8
64 changed files with 1846 additions and 1733 deletions

View File

@ -1,19 +0,0 @@
Flash Stubs
===========
For most of the targets, these are assembler routines for executing
a flash write on the supported targets. They are kept here for
reference, but are not used, as the compiled binary code is included
in the target drivers.
For the STM32l0x, the stubs are written in C++ and emitted as arrays
of half-words for inclusion in the target driver. The use of a higher
level language allows more detailed code and for easy revisions.
These stubs communicate with the driver through a structure defined in
the src/include/stm32l0-nvm.h header.
The dump-to-array.sh helper script uses sed to transform the output of
'objdump -d' into a half-word array of the instructions that may be
included in C code to declare the stub. FWIW, objcopy doesn't produce
the same output as objdump. It omits some of the instructions,
probably because the object file isn't linked.

View File

@ -1,6 +1,6 @@
PROBE_HOST ?= native
PLATFORM_DIR = platforms/$(PROBE_HOST)
VPATH += platforms/common $(PLATFORM_DIR)
VPATH += $(PLATFORM_DIR) platforms/common target
ENABLE_DEBUG ?=
ifneq ($(V), 1)
@ -13,6 +13,7 @@ OPT_FLAGS ?= -O2
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts\
$(OPT_FLAGS) -std=gnu99 -g3 -MD \
-I. -Iinclude -Iplatforms/common -I$(PLATFORM_DIR)
LDFLAGS += $(OPT_FLAGS)
ifeq ($(ENABLE_DEBUG), 1)
CFLAGS += -DENABLE_DEBUG
@ -30,10 +31,12 @@ SRC = \
exception.c \
gdb_if.c \
gdb_main.c \
gdb_hostio.c \
gdb_packet.c \
hex_utils.c \
jtag_scan.c \
jtagtap.c \
jtagtap_generic.c \
lmi.c \
lpc_common.c \
lpc11xx.c \
@ -51,6 +54,7 @@ SRC = \
stm32l0.c \
stm32l4.c \
swdptap.c \
swdptap_generic.c \
target.c \
include $(PLATFORM_DIR)/Makefile.inc

View File

@ -26,22 +26,29 @@
#include "exception.h"
#include "command.h"
#include "gdb_packet.h"
#include "jtag_scan.h"
#include "target.h"
#include "morse.h"
#include "adiv5.h"
#include "version.h"
#ifdef PLATFORM_HAS_TRACESWO
# include "traceswo.h"
#endif
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
struct command_s {
const char *cmd;
cmd_handler handler;
const char *help;
};
static bool cmd_version(void);
static bool cmd_help(target *t);
static bool cmd_jtag_scan(target *t, int argc, char **argv);
static bool cmd_swdp_scan(void);
static bool cmd_targets(target *t);
static bool cmd_targets(void);
static bool cmd_morse(void);
static bool cmd_connect_srst(target *t, int argc, const char **argv);
static bool cmd_hard_srst(void);
@ -83,7 +90,6 @@ bool debug_bmp;
int command_process(target *t, char *cmd)
{
struct target_command_s *tc;
const struct command_s *c;
int argc = 0;
const char **argv;
@ -103,19 +109,14 @@ int command_process(target *t, char *cmd)
/* Accept a partial match as GDB does.
* So 'mon ver' will match 'monitor version'
*/
if(!strncmp(argv[0], c->cmd, strlen(argv[0])))
if ((argc == 0) || !strncmp(argv[0], c->cmd, strlen(argv[0])))
return !c->handler(t, argc, argv);
}
if (!t)
return -1;
for (tc = t->commands; tc; tc = tc->next)
for(c = tc->cmds; c->cmd; c++)
if(!strncmp(argv[0], c->cmd, strlen(argv[0])))
return !c->handler(t, argc, argv);
return -1;
return target_command(t, argc, argv);
}
bool cmd_version(void)
@ -130,7 +131,6 @@ bool cmd_version(void)
bool cmd_help(target *t)
{
struct target_command_s *tc;
const struct command_s *c;
gdb_out("General commands:\n");
@ -140,11 +140,7 @@ bool cmd_help(target *t)
if (!t)
return -1;
for (tc = t->commands; tc; tc = tc->next) {
gdb_outf("%s specific commands:\n", tc->specific_name);
for(c = tc->cmds; c->cmd; c++)
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
}
target_command_help(t);
return true;
}
@ -185,13 +181,7 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
gdb_out("JTAG device scan failed!\n");
return false;
}
gdb_outf("Device IR Len IDCODE Description\n");
for(int i = 0; i < jtag_dev_count; i++)
gdb_outf("%d\t%d\t0x%08lX %s\n", i,
jtag_devs[i].ir_len, jtag_devs[i].idcode,
jtag_devs[i].descr);
gdb_out("\n");
cmd_targets(NULL);
cmd_targets();
return true;
}
@ -222,27 +212,26 @@ bool cmd_swdp_scan(void)
return false;
}
cmd_targets(NULL);
cmd_targets();
return true;
}
bool cmd_targets(target *cur_target)
static void display_target(int i, target *t, void *context)
{
struct target_s *t;
int i;
(void)context;
gdb_outf("%2d %c %s\n", i, target_attached(t)?'*':' ', target_driver_name(t));
}
if(!target_list) {
bool cmd_targets(void)
{
gdb_out("Available Targets:\n");
gdb_out("No. Att Driver\n");
if (!target_foreach(display_target, NULL)) {
gdb_out("No usable targets found.\n");
return false;
}
gdb_out("Available Targets:\n");
gdb_out("No. Att Driver\n");
for(t = target_list, i = 1; t; t = t->next, i++)
gdb_outf("%2d %c %s\n", i, t==cur_target?'*':' ',
t->driver);
return true;
}

View File

@ -89,23 +89,21 @@ static const uint32_t crc32_table[] = {
0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4,
};
uint32_t crc32_calc(uint32_t crc, uint8_t data)
static uint32_t crc32_calc(uint32_t crc, uint8_t data)
{
return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255];
}
uint32_t generic_crc32(target *t, uint32_t base, int len)
uint32_t generic_crc32(target *t, uint32_t base, size_t len)
{
uint32_t crc = -1;
static uint8_t bytes[128];
uint8_t bytes[128];
while (len) {
uint32_t i;
uint32_t read_len = len >= 128 ? 128 : len;
size_t read_len = MIN(sizeof(bytes), len);
target_mem_read(t, bytes, base, read_len);
for (i=0; i<read_len; i++)
for (unsigned i = 0; i < read_len; i++)
crc = crc32_calc(crc, bytes[i]);
base += read_len;
@ -115,29 +113,31 @@ uint32_t generic_crc32(target *t, uint32_t base, int len)
}
#else
#include <libopencm3/stm32/crc.h>
uint32_t generic_crc32(target *t, uint32_t base, int len)
uint32_t generic_crc32(target *t, uint32_t base, size_t len)
{
uint32_t data;
uint8_t bytes[128];
uint32_t crc;
size_t i;
CRC_CR |= CRC_CR_RESET;
while (len > 3) {
data = target_mem_read32(t, base);
size_t read_len = MIN(sizeof(bytes), len) & ~3;
target_mem_read(t, bytes, base, read_len);
CRC_DR = __builtin_bswap32(data);
base += 4;
len -= 4;
for (unsigned i = 0; i < read_len; i += 4)
CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i));
base += read_len;
len -= read_len;
}
crc = CRC_DR;
target_mem_read(t, bytes, base, len);
uint8_t *data = bytes;
while (len--) {
data = target_mem_read8(t, base++);
crc ^= data << 24;
for (i = 0; i < 8; i++) {
crc ^= *data++ << 24;
for (int i = 0; i < 8; i++) {
if (crc & 0x80000000)
crc = (crc << 1) ^ 0x4C11DB7;
else
@ -146,5 +146,5 @@ uint32_t generic_crc32(target *t, uint32_t base, int len)
}
return crc;
}
#endif

133
src/gdb_hostio.c Normal file
View File

@ -0,0 +1,133 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
#include "general.h"
#include "target.h"
#include "gdb_main.h"
#include "gdb_hostio.h"
#include "gdb_packet.h"
int gdb_main_loop(struct target_controller *, bool in_syscall);
int hostio_reply(struct target_controller *tc, char *pbuf, int len)
{
(void)len;
int retcode, items, errno_;
char c, *p;
if (pbuf[1] == '-')
p = &pbuf[2];
else
p = &pbuf[1];
items = sscanf(p, "%x,%x,%c", &retcode, &errno_, &c);
if (pbuf[1] == '-')
retcode = -retcode;
/* if break is requested */
tc->interrupted = items == 3 && c == 'C';
tc->errno_ = errno_;
return retcode;
}
/* Interface to host system calls */
int hostio_open(struct target_controller *tc,
target_addr path, size_t path_len,
enum target_open_flags flags, mode_t mode)
{
gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X", path, path_len, flags, mode);;;;
return gdb_main_loop(tc, true);
}
int hostio_close(struct target_controller *tc, int fd)
{
gdb_putpacket_f("Fclose,%08X", fd);
return gdb_main_loop(tc, true);
}
int hostio_read(struct target_controller *tc,
int fd, target_addr buf, unsigned int count)
{
gdb_putpacket_f("Fread,%08X,%08X,%08X", fd, buf, count);
return gdb_main_loop(tc, true);
}
int hostio_write(struct target_controller *tc,
int fd, target_addr buf, unsigned int count)
{
gdb_putpacket_f("Fwrite,%08X,%08X,%08X", fd, buf, count);
return gdb_main_loop(tc, true);
}
long hostio_lseek(struct target_controller *tc,
int fd, long offset, enum target_seek_flag flag)
{
gdb_putpacket_f("Flseek,%08X,%08X,%08X", fd, offset, flag);
return gdb_main_loop(tc, true);
}
int hostio_rename(struct target_controller *tc,
target_addr oldpath, size_t old_len,
target_addr newpath, size_t new_len)
{
gdb_putpacket_f("Frename,%08X/%X,%08X/%X",
oldpath, old_len, newpath, new_len);
return gdb_main_loop(tc, true);
}
int hostio_unlink(struct target_controller *tc,
target_addr path, size_t path_len)
{
gdb_putpacket_f("Funlink,%08X/%X", path, path_len);
return gdb_main_loop(tc, true);
}
int hostio_stat(struct target_controller *tc,
target_addr path, size_t path_len, target_addr buf)
{
gdb_putpacket_f("Fstat,%08X/%X,%08X", path, path_len, buf);
return gdb_main_loop(tc, true);
}
int hostio_fstat(struct target_controller *tc, int fd, target_addr buf)
{
gdb_putpacket_f("Ffstat,%X,%08X", fd, buf);
return gdb_main_loop(tc, true);
}
int hostio_gettimeofday(struct target_controller *tc,
target_addr tv, target_addr tz)
{
gdb_putpacket_f("Fgettimeofday,%08X,%08X", tv, tz);
return gdb_main_loop(tc, true);
}
int hostio_isatty(struct target_controller *tc, int fd)
{
gdb_putpacket_f("Fisatty,%08X", fd);
return gdb_main_loop(tc, true);
}
int hostio_system(struct target_controller *tc,
target_addr cmd, size_t cmd_len)
{
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
return gdb_main_loop(tc, true);
}

53
src/gdb_hostio.h Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
#ifndef __GDB_SYSCALLS_H
#define __GDB_SYSCALLS_H
#include "target.h"
int hostio_reply(struct target_controller *tc, char *packet, int len);
/* Interface to host system calls */
int hostio_open(struct target_controller *,
target_addr path, size_t path_len,
enum target_open_flags flags, mode_t mode);
int hostio_close(struct target_controller *, int fd);
int hostio_read(struct target_controller *,
int fd, target_addr buf, unsigned int count);
int hostio_write(struct target_controller *,
int fd, target_addr buf, unsigned int count);
long hostio_lseek(struct target_controller *,
int fd, long offset, enum target_seek_flag flag);
int hostio_rename(struct target_controller *,
target_addr oldpath, size_t old_len,
target_addr newpath, size_t new_len);
int hostio_unlink(struct target_controller *,
target_addr path, size_t path_len);
int hostio_stat(struct target_controller *,
target_addr path, size_t path_len, target_addr buf);
int hostio_fstat(struct target_controller *, int fd, target_addr buf);
int hostio_gettimeofday(struct target_controller *,
target_addr tv, target_addr tz);
int hostio_isatty(struct target_controller *, int fd);
int hostio_system(struct target_controller *,
target_addr cmd, size_t cmd_len);
#endif

View File

@ -29,13 +29,18 @@
#include "gdb_if.h"
#include "gdb_packet.h"
#include "gdb_main.h"
#include "jtagtap.h"
#include "jtag_scan.h"
#include "adiv5.h"
#include "gdb_hostio.h"
#include "target.h"
#include "command.h"
#include "crc32.h"
enum gdb_signal {
GDB_SIGINT = 2,
GDB_SIGTRAP = 5,
GDB_SIGSEGV = 11,
GDB_SIGLOST = 29,
};
#define BUF_SIZE 1024
#define ERROR_IF_NO_TARGET() \
@ -50,8 +55,9 @@ static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, int len);
static void handle_z_packet(char *packet, int len);
static void gdb_target_destroy_callback(target *t)
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
{
(void)tc;
if (cur_target == t)
cur_target = NULL;
@ -59,12 +65,35 @@ static void gdb_target_destroy_callback(target *t)
last_target = NULL;
}
void
gdb_main(void)
static void gdb_target_printf(struct target_controller *tc,
const char *fmt, va_list ap)
{
(void)tc;
gdb_voutf(fmt, ap);
}
static struct target_controller gdb_controller = {
.destroy_callback = gdb_target_destroy_callback,
.printf = gdb_target_printf,
.open = hostio_open,
.close = hostio_close,
.read = hostio_read,
.write = hostio_write,
.lseek = hostio_lseek,
.rename = hostio_rename,
.unlink = hostio_unlink,
.stat = hostio_stat,
.fstat = hostio_fstat,
.gettimeofday = hostio_gettimeofday,
.isatty = hostio_isatty,
.system = hostio_system,
};
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{
int size;
bool single_step = false;
char last_activity = 0;
DEBUG("Entring GDB protocol main loop\n");
/* GDB protocol main loop */
@ -72,7 +101,6 @@ gdb_main(void)
SET_IDLE_STATE(1);
size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0);
continue_activity:
switch(pbuf[0]) {
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
@ -89,8 +117,7 @@ gdb_main(void)
sscanf(pbuf, "m%" SCNx32 ",%" SCNx32, &addr, &len);
DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
uint8_t mem[len];
target_mem_read(cur_target, mem, addr, len);
if(target_check_error(cur_target))
if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01");
else
gdb_putpacket(hexify(pbuf, mem, len), len*2);
@ -112,8 +139,7 @@ gdb_main(void)
DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
uint8_t mem[len];
unhexify(mem, pbuf + hex, len);
target_mem_write(cur_target, addr, mem, len);
if(target_check_error(cur_target))
if (target_mem_write(cur_target, addr, mem, len))
gdb_putpacketz("E01");
else
gdb_putpacketz("OK");
@ -135,8 +161,8 @@ gdb_main(void)
case '?': { /* '?': Request reason for target halt */
/* This packet isn't documented as being mandatory,
* but GDB doesn't work without it. */
uint32_t watch_addr;
int sig;
target_addr watch;
enum target_halt_reason reason;
if(!cur_target) {
/* Report "target exited" if no target */
@ -144,58 +170,42 @@ gdb_main(void)
break;
}
last_activity = pbuf[0];
/* Wait for target halt */
while(!(sig = target_halt_wait(cur_target))) {
while(!(reason = target_halt_poll(cur_target, &watch))) {
unsigned char c = gdb_if_getchar_to(0);
if((c == '\x03') || (c == '\x04')) {
target_halt_request(cur_target);
last_activity = 's';
}
}
SET_RUN_STATE(0);
/* Negative signal indicates we're in a syscall */
if (sig < 0)
/* Translate reason to GDB signal */
switch (reason) {
case TARGET_HALT_ERROR:
gdb_putpacket_f("X%02X", GDB_SIGLOST);
break;
/* Target disappeared */
if (cur_target == NULL) {
gdb_putpacket_f("X%02X", sig);
case TARGET_HALT_REQUEST:
gdb_putpacket_f("T%02X", GDB_SIGINT);
break;
}
/* Report reason for halt */
if(target_check_hw_wp(cur_target, &watch_addr)) {
/* Watchpoint hit */
gdb_putpacket_f("T%02Xwatch:%08X;", sig, watch_addr);
} else {
gdb_putpacket_f("T%02X", sig);
case TARGET_HALT_WATCHPOINT:
gdb_putpacket_f("T%02Xwatch:%08X;", GDB_SIGTRAP, watch);
break;
case TARGET_HALT_FAULT:
gdb_putpacket_f("T%02X", GDB_SIGSEGV);
break;
default:
gdb_putpacket_f("T%02X", GDB_SIGTRAP);
}
break;
}
case 'F': { /* Semihosting call finished */
int retcode, errcode, items;
char c, *p;
if (pbuf[1] == '-')
p = &pbuf[2];
else
p = &pbuf[1];
items = sscanf(p, "%x,%x,%c", &retcode, &errcode, &c);
if (pbuf[1] == '-')
retcode = -retcode;
target_hostio_reply(cur_target, retcode, errcode);
/* if break is requested */
if (items == 3 && c == 'C') {
gdb_putpacketz("T02");
break;
case 'F': /* Semihosting call finished */
if (in_syscall) {
return hostio_reply(tc, pbuf, size);
} else {
DEBUG("*** F packet when not in syscall! '%s'\n", pbuf);
gdb_putpacketz("");
}
pbuf[0] = last_activity;
goto continue_activity;
}
break;
/* Optional GDB packet support */
case '!': /* Enable Extended GDB Protocol. */
@ -230,7 +240,7 @@ gdb_main(void)
target_reset(cur_target);
else if(last_target) {
cur_target = target_attach(last_target,
gdb_target_destroy_callback);
&gdb_controller);
target_reset(cur_target);
}
break;
@ -241,8 +251,7 @@ gdb_main(void)
ERROR_IF_NO_TARGET();
sscanf(pbuf, "X%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &bin);
DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
target_mem_write(cur_target, addr, pbuf+bin, len);
if(target_check_error(cur_target))
if (target_mem_write(cur_target, addr, pbuf+bin, len))
gdb_putpacketz("E01");
else
gdb_putpacketz("OK");
@ -326,7 +335,7 @@ handle_q_packet(char *packet, int len)
if((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = target_attach(last_target,
gdb_target_destroy_callback);
&gdb_controller);
}
if (!cur_target) {
gdb_putpacketz("E01");
@ -339,7 +348,7 @@ handle_q_packet(char *packet, int len)
if((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = target_attach(last_target,
gdb_target_destroy_callback);
&gdb_controller);
}
if (!cur_target) {
gdb_putpacketz("E01");
@ -368,14 +377,7 @@ handle_v_packet(char *packet, int plen)
if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
/* Attach to remote target processor */
target *t;
uint32_t i;
for(t = target_list, i = 1; t; t = t->next, i++)
if(i == addr) {
cur_target = target_attach(t,
gdb_target_destroy_callback);
break;
}
cur_target = target_attach_n(addr, &gdb_controller);
if(cur_target)
gdb_putpacketz("T05");
else
@ -388,7 +390,7 @@ handle_v_packet(char *packet, int plen)
gdb_putpacketz("T05");
} else if(last_target) {
cur_target = target_attach(last_target,
gdb_target_destroy_callback);
&gdb_controller);
/* If we were able to attach to the target again */
if (cur_target) {
@ -449,31 +451,22 @@ handle_z_packet(char *packet, int plen)
//sscanf(packet, "%*[zZ]%hhd,%08lX,%hhd", &type, &addr, &len);
type = packet[1] - '0';
sscanf(packet + 2, ",%" PRIx32 ",%d", &addr, &len);
switch(type) {
case 1: /* Hardware breakpoint */
if(set)
ret = target_set_hw_bp(cur_target, addr, len);
else
ret = target_clear_hw_bp(cur_target, addr, len);
break;
case 2:
case 3:
case 4:
if(set)
ret = target_set_hw_wp(cur_target, type, addr, len);
else
ret = target_clear_hw_wp(cur_target, type, addr, len);
break;
default:
gdb_putpacketz("");
return;
}
if(!ret)
gdb_putpacketz("OK");
if(set)
ret = target_breakwatch_set(cur_target, type, addr, len);
else
ret = target_breakwatch_clear(cur_target, type, addr, len);
if (ret < 0) {
gdb_putpacketz("E01");
} else if (ret > 0) {
gdb_putpacketz("");
} else {
gdb_putpacketz("OK");
}
}
void gdb_main(void)
{
gdb_main_loop(&gdb_controller, false);
}

View File

@ -153,16 +153,21 @@ void gdb_out(const char *buf)
gdb_putpacket(hexdata, i);
}
void gdb_outf(const char *fmt, ...)
void gdb_voutf(const char *fmt, va_list ap)
{
va_list ap;
char *buf;
va_start(ap, fmt);
if (vasprintf(&buf, fmt, ap) < 0)
return;
gdb_out(buf);
free(buf);
va_end(ap);
}
void gdb_outf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
gdb_voutf(fmt, ap);
va_end(ap);
}

View File

@ -24,14 +24,6 @@
#include "target.h"
int command_process(target *t, char *cmd);
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
struct command_s {
const char *cmd;
cmd_handler handler;
const char *help;
};
#endif

View File

@ -21,7 +21,6 @@
#ifndef __CRC32_H
#define __CRC32_H
uint32_t crc32_calc(uint32_t crc, uint8_t data);
uint32_t generic_crc32(target *t, uint32_t base, int len);
#endif

View File

@ -21,12 +21,15 @@
#ifndef __GDB_PACKET_H
#define __GDB_PACKET_H
#include <stdarg.h>
int gdb_getpacket(char *packet, int size);
void gdb_putpacket(const char *packet, int size);
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
void gdb_putpacket_f(const char *packet, ...);
void gdb_out(const char *buf);
void gdb_voutf(const char *fmt, va_list);
void gdb_outf(const char *fmt, ...);
#endif

View File

@ -1,190 +0,0 @@
/* @file stm32lx-nvm.h
*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2014 Woollysoft
* Written by Marc Singer <elf@woollysoft.com>
*
* 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/>.
*/
#if !defined (STM32Lx_NVM_H_INCLUDED)
# define STM32Lx_NVM_H_INCLUDED
/* ----- Includes */
#include <stdint.h>
/* ----- Macros */
/* ----- Types */
enum {
STM32Lx_STUB_PHYS = 0x20000000ul,
STM32Lx_STUB_INFO_PHYS = 0x20000004ul,
STM32Lx_STUB_DATA_PHYS = (0x20000000ul + 1024),
STM32Lx_STUB_DATA_MAX = 2048,
STM32Lx_NVM_OPT_PHYS = 0x1ff80000ul,
STM32Lx_NVM_EEPROM_PHYS = 0x08080000ul,
STM32L0_NVM_PHYS = 0x40022000ul,
STM32L0_NVM_PROG_PAGE_SIZE = 128,
STM32L0_NVM_DATA_PAGE_SIZE = 4,
STM32L0_NVM_OPT_SIZE = 12,
STM32L0_NVM_EEPROM_SIZE = 2*1024,
STM32L1_NVM_PHYS = 0x40023c00ul,
STM32L1_NVM_PROG_PAGE_SIZE = 256,
STM32L1_NVM_DATA_PAGE_SIZE = 4,
STM32L1_NVM_OPT_SIZE = 32,
STM32L1_NVM_EEPROM_SIZE = 16*1024,
STM32Lx_NVM_PEKEY1 = 0x89abcdeful,
STM32Lx_NVM_PEKEY2 = 0x02030405ul,
STM32Lx_NVM_PRGKEY1 = 0x8c9daebful,
STM32Lx_NVM_PRGKEY2 = 0x13141516ul,
STM32Lx_NVM_OPTKEY1 = 0xfbead9c8ul,
STM32Lx_NVM_OPTKEY2 = 0x24252627ul,
STM32Lx_NVM_PECR_OBL_LAUNCH = (1<<18),
STM32Lx_NVM_PECR_ERRIE = (1<<17),
STM32Lx_NVM_PECR_EOPIE = (1<<16),
STM32Lx_NVM_PECR_FPRG = (1<<10),
STM32Lx_NVM_PECR_ERASE = (1<< 9),
STM32Lx_NVM_PECR_FIX = (1<< 8), /* FTDW */
STM32Lx_NVM_PECR_DATA = (1<< 4),
STM32Lx_NVM_PECR_PROG = (1<< 3),
STM32Lx_NVM_PECR_OPTLOCK = (1<< 2),
STM32Lx_NVM_PECR_PRGLOCK = (1<< 1),
STM32Lx_NVM_PECR_PELOCK = (1<< 0),
STM32Lx_NVM_SR_FWWERR = (1<<17),
STM32Lx_NVM_SR_NOTZEROERR = (1<<16),
STM32Lx_NVM_SR_RDERR = (1<<13),
STM32Lx_NVM_SR_OPTVER = (1<<11),
STM32Lx_NVM_SR_SIZERR = (1<<10),
STM32Lx_NVM_SR_PGAERR = (1<<9),
STM32Lx_NVM_SR_WRPERR = (1<<8),
STM32Lx_NVM_SR_READY = (1<<3),
STM32Lx_NVM_SR_HWOFF = (1<<2),
STM32Lx_NVM_SR_EOP = (1<<1),
STM32Lx_NVM_SR_BSY = (1<<0),
STM32Lx_NVM_SR_ERR_M = ( STM32Lx_NVM_SR_WRPERR
| STM32Lx_NVM_SR_PGAERR
| STM32Lx_NVM_SR_SIZERR
| STM32Lx_NVM_SR_NOTZEROERR),
STM32L0_NVM_OPTR_BOOT1 = (1<<31),
STM32L0_NVM_OPTR_WDG_SW = (1<<20),
STM32L0_NVM_OPTR_WPRMOD = (1<<8),
STM32L0_NVM_OPTR_RDPROT_S = (0),
STM32L0_NVM_OPTR_RDPROT_M = (0xff),
STM32L0_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L0_NVM_OPTR_RDPROT_2 = (0xcc),
STM32L1_NVM_OPTR_nBFB2 = (1<<23),
STM32L1_NVM_OPTR_nRST_STDBY = (1<<22),
STM32L1_NVM_OPTR_nRST_STOP = (1<<21),
STM32L1_NVM_OPTR_WDG_SW = (1<<20),
STM32L1_NVM_OPTR_BOR_LEV_S = (16),
STM32L1_NVM_OPTR_BOR_LEV_M = (0xf),
STM32L1_NVM_OPTR_SPRMOD = (1<<8),
STM32L1_NVM_OPTR_RDPROT_S = (0),
STM32L1_NVM_OPTR_RDPROT_M = (0xff),
STM32L1_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L1_NVM_OPTR_RDPROT_2 = (0xcc),
};
#if defined (__cplusplus)
namespace STM32 {
struct NVM {
volatile uint32_t acr;
volatile uint32_t pecr;
volatile uint32_t pdkeyr;
volatile uint32_t pkeyr;
volatile uint32_t prgkeyr;
volatile uint32_t optkeyr;
volatile uint32_t sr;
volatile uint32_t optr;
volatile uint32_t wrprot;
static constexpr uint32_t PKEY1 = 0x89abcdef;
static constexpr uint32_t PKEY2 = 0x02030405;
static constexpr uint32_t PRGKEY1 = 0x8c9daebf;
static constexpr uint32_t PRGKEY2 = 0x13141516;
static constexpr uint32_t OPTKEY1 = 0xfbead9c8;
static constexpr uint32_t OPTKEY2 = 0x24252627;
static constexpr uint32_t PDKEY1 = 0x04152637;
static constexpr uint32_t PDKEY2 = 0xfafbfcfd;
};
static_assert(sizeof (NVM) == 9*4, "NVM size error");
}
using stm32lx_stub_pointer_t = uint32_t*;
#define Nvm(nvm) (*reinterpret_cast<STM32::NVM*>(nvm))
#define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS))
namespace {
inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) {
// Lock guarantees unlock
nvm.pecr = STM32Lx_NVM_PECR_PELOCK;
nvm.pkeyr = STM32::NVM::PKEY1;
nvm.pkeyr = STM32::NVM::PKEY2;
nvm.prgkeyr = STM32::NVM::PRGKEY1;
nvm.prgkeyr = STM32::NVM::PRGKEY2;
return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
}
inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
}
#else
typedef uint32_t stm32lx_stub_pointer_t;
#define STM32Lx_NVM_PECR(p) ((p) + 0x04)
#define STM32Lx_NVM_PEKEYR(p) ((p) + 0x0C)
#define STM32Lx_NVM_PRGKEYR(p) ((p) + 0x10)
#define STM32Lx_NVM_OPTKEYR(p) ((p) + 0x14)
#define STM32Lx_NVM_SR(p) ((p) + 0x18)
#define STM32Lx_NVM_OPTR(p) ((p) + 0x1C)
#endif
enum {
OPT_STM32L1 = 1<<1,
};
struct stm32lx_nvm_stub_info {
stm32lx_stub_pointer_t destination;
int32_t size;
stm32lx_stub_pointer_t source;
uint32_t nvm;
uint16_t page_size;
uint16_t options;
} __attribute__((packed));
/* ----- Globals */
/* ----- Prototypes */
#endif /* STM32Lx_NVM_H_INCLUDED */

View File

@ -22,10 +22,14 @@
#define __SWDPTAP_H
int swdptap_init(void);
void swdptap_reset(void);
/* Primitive functions */
bool swdptap_bit_in(void);
void swdptap_bit_out(bool val);
/* High level functions, provided as weak in swdptap_generic.c */
uint32_t swdptap_seq_in(int ticks);
uint8_t swdptap_seq_in_parity(uint32_t *data, int ticks);
bool swdptap_seq_in_parity(uint32_t *data, int ticks);
void swdptap_seq_out(uint32_t MS, int ticks);
void swdptap_seq_out_parity(uint32_t MS, int ticks);

View File

@ -1,7 +1,7 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* This program is free software: you can redistribute it and/or modify
@ -25,252 +25,140 @@
#ifndef __TARGET_H
#define __TARGET_H
#include <stdarg.h>
typedef struct target_s target;
typedef uint32_t target_addr;
struct target_controller;
/* The destroy callback function will be called by target_list_free() just
* before the target is free'd. This may be because we're scanning for new
* targets, or because of a communication failure. The target data may
* be assumed to be intact, but the communication medium may not be available,
* so access methods shouldn't be called.
*
* The callback is installed by target_attach() and only removed by attaching
* with a different callback. It remains intact after target_detach().
*/
typedef void (*target_destroy_callback)(target *t);
int adiv5_swdp_scan(void);
int jtag_scan(const uint8_t *lrlens);
/* Halt/resume functions */
target *target_attach(target *t, target_destroy_callback destroy_cb);
bool target_foreach(void (*cb)(int i, target *t, void *context), void *context);
void target_list_free(void);
#define target_detach(target) \
(target)->detach(target)
#define target_check_error(target) \
(target)->check_error(target)
/* Attach/detach functions */
target *target_attach(target *t, struct target_controller *);
target *target_attach_n(int n, struct target_controller *);
void target_detach(target *t);
bool target_attached(target *t);
const char *target_driver_name(target *t);
/* Memory access functions */
#define target_mem_read(target, dest, src, len) \
(target)->mem_read((target), (dest), (src), (len))
#define target_mem_write(target, dest, src, len) \
(target)->mem_write((target), (dest), (src), (len))
/* Register access functions */
#define target_regs_read(target, data) \
(target)->regs_read((target), (data))
#define target_regs_write(target, data) \
(target)->regs_write((target), (data))
/* Halt/resume functions */
#define target_reset(target) \
(target)->reset(target)
#define target_halt_request(target) \
(target)->halt_request(target)
#define target_halt_wait(target) \
(target)->halt_wait(target)
#define target_halt_resume(target, step) \
(target)->halt_resume((target), (step))
/* Break-/watchpoint functions */
#define target_set_hw_bp(target, addr, len) \
(target)->set_hw_bp((target), (addr), (len))
#define target_clear_hw_bp(target, addr, len) \
(target)->clear_hw_bp((target), (addr), (len))
#define target_set_hw_wp(target, type, addr, len) \
(target)->set_hw_wp((target), (type), (addr), (len))
#define target_clear_hw_wp(target, type, addr, len) \
(target)->clear_hw_wp((target), (type), (addr), (len))
#define target_check_hw_wp(target, addr) \
((target)->check_hw_wp?(target)->check_hw_wp((target), (addr)):0)
const char *target_mem_map(target *t);
int target_mem_read(target *t, void *dest, target_addr src, size_t len);
int target_mem_write(target *t, target_addr dest, const void *src, size_t len);
/* Flash memory access functions */
int target_flash_erase(target *t, uint32_t addr, size_t len);
int target_flash_write(target *t,
uint32_t dest, const void *src, size_t len);
int target_flash_erase(target *t, target_addr addr, size_t len);
int target_flash_write(target *t, target_addr dest, const void *src, size_t len);
int target_flash_done(target *t);
/* Host I/O */
#define target_hostio_reply(target, recode, errcode) \
(target)->hostio_reply((target), (retcode), (errcode))
/* Register access functions */
size_t target_regs_size(target *t);
const char *target_tdesc(target *t);
void target_regs_read(target *t, void *data);
void target_regs_write(target *t, const void *data);
/* Accessor functions */
#define target_regs_size(target) \
((target)->regs_size)
#define target_tdesc(target) \
((target)->tdesc ? (target)->tdesc : "")
struct target_ram {
uint32_t start;
uint32_t length;
struct target_ram *next;
/* Halt/resume functions */
enum target_halt_reason {
TARGET_HALT_RUNNING = 0, /* Target not halted */
TARGET_HALT_ERROR, /* Failed to read target status */
TARGET_HALT_REQUEST,
TARGET_HALT_STEPPING,
TARGET_HALT_BREAKPOINT,
TARGET_HALT_WATCHPOINT,
TARGET_HALT_FAULT,
};
struct target_flash;
typedef int (*flash_erase_func)(struct target_flash *f, uint32_t addr, size_t len);
typedef int (*flash_write_func)(struct target_flash *f, uint32_t dest,
const void *src, size_t len);
typedef int (*flash_done_func)(struct target_flash *f);
struct target_flash {
uint32_t start;
uint32_t length;
uint32_t blocksize;
flash_erase_func erase;
flash_write_func write;
flash_done_func done;
target *t;
struct target_flash *next;
int align;
uint8_t erased;
void target_reset(target *t);
void target_halt_request(target *t);
enum target_halt_reason target_halt_poll(target *t, target_addr *watch);
void target_halt_resume(target *t, bool step);
/* For buffered flash */
size_t buf_size;
flash_write_func write_buf;
uint32_t buf_addr;
void *buf;
/* Break-/watchpoint functions */
enum target_breakwatch {
TARGET_BREAK_SOFT,
TARGET_BREAK_HARD,
TARGET_WATCH_WRITE,
TARGET_WATCH_READ,
TARGET_WATCH_ACCESS,
};
int target_breakwatch_set(target *t, enum target_breakwatch, target_addr, size_t);
int target_breakwatch_clear(target *t, enum target_breakwatch, target_addr, size_t);
/* Command interpreter */
void target_command_help(target *t);
int target_command(target *t, int argc, const char *argv[]);
enum target_errno {
TARGET_EPERM = 1,
TARGET_ENOENT = 2,
TARGET_EINTR = 4,
TARGET_EBADF = 9,
TARGET_EACCES = 13,
TARGET_EFAULT = 14,
TARGET_EBUSY = 16,
TARGET_EEXIST = 17,
TARGET_ENODEV = 19,
TARGET_ENOTDIR = 20,
TARGET_EISDIR = 21,
TARGET_EINVAL = 22,
TARGET_EMFILE = 24,
TARGET_ENFILE = 23,
TARGET_EFBIG = 27,
TARGET_ENOSPC = 28,
TARGET_ESPIPE = 29,
TARGET_EROFS = 30,
TARGET_ENAMETOOLONG = 36,
};
struct target_s {
/* Notify controlling debugger if target is lost */
target_destroy_callback destroy_callback;
/* Attach/Detach funcitons */
bool (*attach)(target *t);
void (*detach)(target *t);
bool (*check_error)(target *t);
/* Memory access functions */
void (*mem_read)(target *t, void *dest, uint32_t src,
size_t len);
void (*mem_write)(target *t, uint32_t dest,
const void *src, size_t len);
/* Register access functions */
int regs_size;
const char *tdesc;
void (*regs_read)(target *t, void *data);
void (*regs_write)(target *t, const void *data);
/* Halt/resume functions */
void (*reset)(target *t);
void (*halt_request)(target *t);
int (*halt_wait)(target *t);
void (*halt_resume)(target *t, bool step);
/* Break-/watchpoint functions */
int (*set_hw_bp)(target *t, uint32_t addr, uint8_t len);
int (*clear_hw_bp)(target *t, uint32_t addr, uint8_t len);
int (*set_hw_wp)(target *t, uint8_t type, uint32_t addr, uint8_t len);
int (*clear_hw_wp)(target *t, uint8_t type, uint32_t addr, uint8_t len);
int (*check_hw_wp)(target *t, uint32_t *addr);
/* target-defined options */
unsigned target_options;
uint32_t idcode;
/* Target memory map */
char *dyn_mem_map;
struct target_ram *ram;
struct target_flash *flash;
/* Host I/O support */
void (*hostio_reply)(target *t, int32_t retcode, uint32_t errcode);
const char *driver;
struct target_command_s *commands;
int size;
struct target_s *next;
void *priv;
void (*priv_free)(void *);
enum target_open_flags {
TARGET_O_RDONLY = 0,
TARGET_O_WRONLY = 1,
TARGET_O_RDWR = 2,
TARGET_O_APPEND = 0x008,
TARGET_O_CREAT = 0x200,
TARGET_O_TRUNC = 0x400,
};
struct target_command_s {
const char *specific_name;
const struct command_s *cmds;
struct target_command_s *next;
enum target_seek_flag {
TARGET_SEEK_SET = 0,
TARGET_SEEK_CUR = 1,
TARGET_SEEK_END = 2,
};
extern target *target_list;
struct target_controller {
void (*destroy_callback)(struct target_controller *, target *t);
void (*printf)(struct target_controller *, const char *fmt, va_list);
target *target_new(unsigned size);
void target_list_free(void);
void target_add_commands(target *t, const struct command_s *cmds, const char *name);
void target_add_ram(target *t, uint32_t start, uint32_t len);
void target_add_flash(target *t, struct target_flash *f);
const char *target_mem_map(target *t);
int target_flash_write_buffered(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
int target_flash_done_buffered(struct target_flash *f);
static inline uint32_t target_mem_read32(target *t, uint32_t addr)
{
uint32_t ret;
target_mem_read(t, &ret, addr, sizeof(ret));
return ret;
}
static inline void target_mem_write32(target *t, uint32_t addr, uint32_t value)
{
target_mem_write(t, addr, &value, sizeof(value));
}
static inline uint16_t target_mem_read16(target *t, uint32_t addr)
{
uint16_t ret;
target_mem_read(t, &ret, addr, sizeof(ret));
return ret;
}
static inline void target_mem_write16(target *t, uint32_t addr, uint16_t value)
{
target_mem_write(t, addr, &value, sizeof(value));
}
static inline uint8_t target_mem_read8(target *t, uint32_t addr)
{
uint8_t ret;
target_mem_read(t, &ret, addr, sizeof(ret));
return ret;
}
static inline void target_mem_write8(target *t, uint32_t addr, uint8_t value)
{
target_mem_write(t, addr, &value, sizeof(value));
}
/* Probe for various targets.
* Actual functions implemented in their respective drivers.
*/
bool stm32f1_probe(target *t);
bool stm32f4_probe(target *t);
bool stm32l0_probe(target *t);
bool stm32l1_probe(target *t);
bool stm32l4_probe(target *t);
bool lmi_probe(target *t);
bool lpc11xx_probe(target *t);
bool lpc15xx_probe(target *t);
bool lpc43xx_probe(target *t);
bool sam3x_probe(target *t);
bool nrf51_probe(target *t);
bool samd_probe(target *t);
bool kinetis_probe(target *t);
bool efm32_probe(target *t);
/* Interface to host system calls */
int (*open)(struct target_controller *,
target_addr path, size_t path_len,
enum target_open_flags flags, mode_t mode);
int (*close)(struct target_controller *, int fd);
int (*read)(struct target_controller *,
int fd, target_addr buf, unsigned int count);
int (*write)(struct target_controller *,
int fd, target_addr buf, unsigned int count);
long (*lseek)(struct target_controller *,
int fd, long offset, enum target_seek_flag flag);
int (*rename)(struct target_controller *,
target_addr oldpath, size_t old_len,
target_addr newpath, size_t new_len);
int (*unlink)(struct target_controller *,
target_addr path, size_t path_len);
int (*stat)(struct target_controller *,
target_addr path, size_t path_len, target_addr buf);
int (*fstat)(struct target_controller *, int fd, target_addr buf);
int (*gettimeofday)(struct target_controller *,
target_addr tv, target_addr tz);
int (*isatty)(struct target_controller *, int fd);
int (*system)(struct target_controller *,
target_addr cmd, size_t cmd_len);
enum target_errno errno_;
bool interrupted;
};
#endif

View File

@ -25,8 +25,6 @@
#include "general.h"
#include "gdb_if.h"
#include "gdb_main.h"
#include "jtagtap.h"
#include "jtag_scan.h"
#include "target.h"
#include "exception.h"
#include "gdb_packet.h"

View File

@ -20,24 +20,24 @@
/* This file implements the low-level SW-DP interface. */
#include <stdio.h>
#include "general.h"
#include "swdptap.h"
#include "gdb_packet.h"
int swdptap_init(void)
{
return 0;
}
static void swdptap_turnaround(uint8_t dir)
{
static uint8_t olddir = 0;
DEBUG("%s", dir ? "\n-> ":"\n<- ");
/* Don't turnaround if direction not changing */
if(dir == olddir) return;
olddir = dir;
DEBUG("%s", dir ? "\n-> ":"\n<- ");
if(dir)
SWDIO_MODE_FLOAT();
gpio_set(SWCLK_PORT, SWCLK_PIN);
@ -46,10 +46,12 @@ static void swdptap_turnaround(uint8_t dir)
SWDIO_MODE_DRIVE();
}
static uint8_t swdptap_bit_in(void)
bool swdptap_bit_in(void)
{
uint16_t ret;
swdptap_turnaround(1);
ret = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
@ -59,95 +61,14 @@ static uint8_t swdptap_bit_in(void)
return ret != 0;
}
static void swdptap_bit_out(uint8_t val)
void swdptap_bit_out(bool val)
{
DEBUG("%d", val);
swdptap_turnaround(0);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, val);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
int swdptap_init(void)
{
/* This must be investigated in more detail.
* As described in STM32 Reference Manual... */
swdptap_reset();
swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
swdptap_reset();
swdptap_seq_out(0, 16);
return 0;
}
void swdptap_reset(void)
{
swdptap_turnaround(0);
/* 50 clocks with TMS high */
for(int i = 0; i < 50; i++) swdptap_bit_out(1);
}
uint32_t swdptap_seq_in(int ticks)
{
uint32_t index = 1;
uint32_t ret = 0;
swdptap_turnaround(1);
while(ticks--) {
if(swdptap_bit_in()) ret |= index;
index <<= 1;
}
return ret;
}
uint8_t swdptap_seq_in_parity(uint32_t *ret, int ticks)
{
uint32_t index = 1;
uint8_t parity = 0;
*ret = 0;
swdptap_turnaround(1);
while(ticks--) {
if(swdptap_bit_in()) {
*ret |= index;
parity ^= 1;
}
index <<= 1;
}
if(swdptap_bit_in()) parity ^= 1;
return parity;
}
void swdptap_seq_out(uint32_t MS, int ticks)
{
swdptap_turnaround(0);
while(ticks--) {
swdptap_bit_out(MS & 1);
MS >>= 1;
}
}
void swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t parity = 0;
swdptap_turnaround(0);
while(ticks--) {
swdptap_bit_out(MS & 1);
parity ^= MS;
MS >>= 1;
}
swdptap_bit_out(parity & 1);
}

View File

@ -29,9 +29,7 @@
#include "general.h"
#include "swdptap.h"
static void swdptap_turnaround(uint8_t dir);
static uint8_t swdptap_bit_in(void);
static void swdptap_bit_out(uint8_t val);
static uint8_t olddir = 0;
int swdptap_init(void)
{
@ -46,33 +44,17 @@ int swdptap_init(void)
}
assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2);
/* This must be investigated in more detail.
* As described in STM32 Reference Manual... */
swdptap_seq_out(0xFFFF, 16);
swdptap_reset();
swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
swdptap_reset();
swdptap_seq_out(0, 16);
olddir = 0;
return 0;
}
void swdptap_reset(void)
{
swdptap_turnaround(0);
/* 50 clocks with TMS high */
for(int i = 0; i < 50; i++)
swdptap_bit_out(1);
}
static void swdptap_turnaround(uint8_t dir)
{
static uint8_t olddir = 0;
platform_buffer_flush();
if(dir == olddir) return;
if (dir == olddir)
return;
olddir = dir;
if(dir) /* SWDIO goes to input */
@ -85,10 +67,12 @@ static void swdptap_turnaround(uint8_t dir)
assert(ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG) == 0);
}
static uint8_t swdptap_bit_in(void)
bool swdptap_bit_in(void)
{
uint8_t ret;
swdptap_turnaround(1);
ftdi_read_pins(ftdic, &ret);
ret &= 0x08;
ftdi_write_data(ftdic, (void *)"\xA1\xA0", 2);
@ -96,75 +80,16 @@ static uint8_t swdptap_bit_in(void)
return ret;
}
static void swdptap_bit_out(uint8_t val)
void swdptap_bit_out(bool val)
{
uint8_t buf[3] = "\xA0\xA1\xA0";
if(val) {
swdptap_turnaround(0);
if (val) {
for(int i = 0; i < 3; i++)
buf[i] |= 0x08;
}
platform_buffer_write(buf, 3);
}
uint32_t swdptap_seq_in(int ticks)
{
uint32_t index = 1;
uint32_t ret = 0;
swdptap_turnaround(1);
while (ticks--) {
if (swdptap_bit_in())
ret |= index;
index <<= 1;
}
return ret;
}
uint8_t swdptap_seq_in_parity(uint32_t *ret, int ticks)
{
uint32_t index = 1;
uint8_t parity = 0;
*ret = 0;
swdptap_turnaround(1);
while (ticks--) {
if (swdptap_bit_in()) {
*ret |= index;
parity ^= 1;
}
index <<= 1;
}
if (swdptap_bit_in())
parity ^= 1;
return parity;
}
void swdptap_seq_out(uint32_t MS, int ticks)
{
swdptap_turnaround(0);
while (ticks--) {
swdptap_bit_out(MS & 1);
MS >>= 1;
}
}
void swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t parity = 0;
swdptap_turnaround(0);
while (ticks--) {
swdptap_bit_out(MS & 1);
parity ^= MS;
MS >>= 1;
}
swdptap_bit_out(parity & 1);
}

View File

@ -66,11 +66,3 @@ inline uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDO)
return ret != 0;
}
#define PROVIDE_GENERIC_JTAGTAP_TMS_SEQ
#define PROVIDE_GENERIC_JTAGTAP_TDI_TDO_SEQ
#define PROVIDE_GENERIC_JTAGTAP_TDI_SEQ
#include "jtagtap_generic.c"

View File

@ -41,7 +41,3 @@ jtagtap_next(const uint8_t dTMS, const uint8_t dTDO)
return ret != 0;
}
#define PROVIDE_GENERIC_JTAGTAP_TMS_SEQ
#define PROVIDE_GENERIC_JTAGTAP_TDI_TDO_SEQ
#define PROVIDE_GENERIC_JTAGTAP_TDI_SEQ
#include "jtagtap_generic.c"

View File

@ -1,124 +0,0 @@
#include "general.h"
#include "swdptap.h"
static void swdptap_turnaround(uint8_t dir)
{
static uint8_t olddir = 0;
DEBUG("%s", dir ? "\n-> ":"\n<- ");
/* Don't turnaround if direction not changing */
if(dir == olddir) return;
olddir = dir;
if(dir)
SWDIO_MODE_FLOAT();
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
if(!dir)
SWDIO_MODE_DRIVE();
}
static uint8_t swdptap_bit_in(void)
{
uint16_t ret;
ret = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
DEBUG("%d", ret?1:0);
return ret != 0;
}
static void swdptap_bit_out(uint8_t val)
{
DEBUG("%d", val);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, val);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
int
swdptap_init(void)
{
swdptap_reset();
swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
swdptap_reset();
swdptap_seq_out(0, 16);
return 0;
}
void
swdptap_reset(void)
{
swdptap_turnaround(0);
/* 50 clocks with TMS high */
for(int i = 0; i < 50; i++) swdptap_bit_out(1);
}
uint32_t
swdptap_seq_in(int ticks)
{
uint32_t index = 1;
uint32_t ret = 0;
swdptap_turnaround(1);
while(ticks--) {
if(swdptap_bit_in()) ret |= index;
index <<= 1;
}
return ret;
}
uint8_t
swdptap_seq_in_parity(uint32_t *ret, int ticks)
{
uint32_t index = 1;
uint8_t parity = 0;
*ret = 0;
swdptap_turnaround(1);
while(ticks--) {
if(swdptap_bit_in()) {
*ret |= index;
parity ^= 1;
}
index <<= 1;
}
if(swdptap_bit_in()) parity ^= 1;
return parity;
}
void
swdptap_seq_out(uint32_t MS, int ticks)
{
swdptap_turnaround(0);
while(ticks--) {
swdptap_bit_out(MS & 1);
MS >>= 1;
}
}
void
swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t parity = 0;
swdptap_turnaround(0);
while(ticks--) {
swdptap_bit_out(MS & 1);
parity ^= MS;
MS >>= 1;
}
swdptap_bit_out(parity & 1);
}

View File

@ -1,257 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2012 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
#include "general.h"
#include "target.h"
target *target_list = NULL;
target *target_new(unsigned size)
{
target *t = (void*)calloc(1, size);
t->next = target_list;
target_list = t;
return t;
}
void target_list_free(void)
{
struct target_command_s *tc;
while(target_list) {
target *t = target_list->next;
if (target_list->destroy_callback)
target_list->destroy_callback(target_list);
if (target_list->priv)
target_list->priv_free(target_list->priv);
while (target_list->commands) {
tc = target_list->commands->next;
free(target_list->commands);
target_list->commands = tc;
}
if (target_list->dyn_mem_map)
free(target_list->dyn_mem_map);
while (target_list->ram) {
void * next = target_list->ram->next;
free(target_list->ram);
target_list->ram = next;
}
while (target_list->flash) {
void * next = target_list->flash->next;
if (target_list->flash->buf)
free(target_list->flash->buf);
free(target_list->flash);
target_list->flash = next;
}
free(target_list);
target_list = t;
}
}
void target_add_commands(target *t, const struct command_s *cmds, const char *name)
{
struct target_command_s *tc;
if (t->commands) {
for (tc = t->commands; tc->next; tc = tc->next);
tc = tc->next = malloc(sizeof(*tc));
} else {
t->commands = tc = malloc(sizeof(*tc));
}
tc->specific_name = name;
tc->cmds = cmds;
tc->next = NULL;
}
target *target_attach(target *t, target_destroy_callback destroy_cb)
{
if (t->destroy_callback)
t->destroy_callback(t);
t->destroy_callback = destroy_cb;
if (!t->attach(t))
return NULL;
return t;
}
void target_add_ram(target *t, uint32_t start, uint32_t len)
{
struct target_ram *ram = malloc(sizeof(*ram));
ram->start = start;
ram->length = len;
ram->next = t->ram;
t->ram = ram;
}
void target_add_flash(target *t, struct target_flash *f)
{
f->t = t;
f->next = t->flash;
t->flash = f;
}
static ssize_t map_ram(char *buf, size_t len, struct target_ram *ram)
{
return snprintf(buf, len, "<memory type=\"ram\" start=\"0x%08"PRIx32
"\" length=\"0x%08"PRIx32"\"/>",
ram->start, ram->length);
}
static ssize_t map_flash(char *buf, size_t len, struct target_flash *f)
{
int i = 0;
i += snprintf(&buf[i], len - i, "<memory type=\"flash\" start=\"0x%08"PRIx32
"\" length=\"0x%08"PRIx32"\">",
f->start, f->length);
i += snprintf(&buf[i], len - i, "<property name=\"blocksize\">0x%08"PRIx32
"</property></memory>",
f->blocksize);
return i;
}
const char *target_mem_map(target *t)
{
if (t->dyn_mem_map)
return t->dyn_mem_map;
/* FIXME size buffer */
size_t len = 1024;
char *tmp = malloc(len);
size_t i = 0;
i = snprintf(&tmp[i], len - i, "<memory-map>");
/* Map each defined RAM */
for (struct target_ram *r = t->ram; r; r = r->next)
i += map_ram(&tmp[i], len - i, r);
/* Map each defined Flash */
for (struct target_flash *f = t->flash; f; f = f->next)
i += map_flash(&tmp[i], len - i, f);
i += snprintf(&tmp[i], len - i, "</memory-map>");
t->dyn_mem_map = tmp;
return t->dyn_mem_map;
}
static struct target_flash *flash_for_addr(target *t, uint32_t addr)
{
for (struct target_flash *f = t->flash; f; f = f->next)
if ((f->start <= addr) &&
(addr < (f->start + f->length)))
return f;
return NULL;
}
int target_flash_erase(target *t, uint32_t addr, size_t len)
{
int ret = 0;
while (len) {
struct target_flash *f = flash_for_addr(t, addr);
size_t tmplen = MIN(len, f->length - (addr % f->length));
ret |= f->erase(f, addr, tmplen);
addr += tmplen;
len -= tmplen;
}
return ret;
}
int target_flash_write(target *t,
uint32_t dest, const void *src, size_t len)
{
int ret = 0;
while (len) {
struct target_flash *f = flash_for_addr(t, dest);
size_t tmplen = MIN(len, f->length - (dest % f->length));
if (f->align > 1) {
uint32_t offset = dest % f->align;
uint8_t data[ALIGN(offset + len, f->align)];
memset(data, f->erased, sizeof(data));
memcpy((uint8_t *)data + offset, src, len);
ret |= f->write(f, dest - offset, data, sizeof(data));
} else {
ret |= f->write(f, dest, src, tmplen);
}
src += tmplen;
len -= tmplen;
}
return ret;
}
int target_flash_done(target *t)
{
for (struct target_flash *f = t->flash; f; f = f->next) {
if (f->done) {
int tmp = f->done(f);
if (tmp)
return tmp;
}
}
return 0;
}
int target_flash_write_buffered(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
{
int ret = 0;
if (f->buf == NULL) {
/* Allocate flash sector buffer */
f->buf = malloc(f->buf_size);
f->buf_addr = -1;
}
while (len) {
uint32_t offset = dest % f->buf_size;
uint32_t base = dest - offset;
if (base != f->buf_addr) {
if (f->buf_addr != (uint32_t)-1) {
/* Write sector to flash if valid */
ret |= f->write_buf(f, f->buf_addr,
f->buf, f->buf_size);
}
/* Setup buffer for a new sector */
f->buf_addr = base;
memset(f->buf, f->erased, f->buf_size);
}
/* Copy chunk into sector buffer */
size_t sectlen = MIN(f->buf_size - offset, len);
memcpy(f->buf + offset, src, sectlen);
dest += sectlen;
src += sectlen;
len -= sectlen;
}
return ret;
}
int target_flash_done_buffered(struct target_flash *f)
{
int ret = 0;
if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) {
/* Write sector to flash if valid */
ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size);
f->buf_addr = -1;
free(f->buf);
f->buf = NULL;
}
return ret;
}

View File

@ -22,8 +22,8 @@
* ARM Debug Interface v5 Architecure Specification, ARM doc IHI0031A.
*/
#include "general.h"
#include "jtag_scan.h"
#include "gdb_packet.h"
#include "target.h"
#include "target_internal.h"
#include "adiv5.h"
#include "cortexm.h"
#include "exception.h"
@ -277,8 +277,6 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr)
/* Extract Component ID class nibble */
uint32_t cid_class = (cidr & CID_CLASS_MASK) >> CID_CLASS_SHIFT;
DEBUG("0x%X: \"%s\"\n", addr, cidc_debug_strings[cid_class]);
if (cid_class == cidc_romtab) { /* ROM table, probe recursively */
for (int i = 0; i < 256; i++) {
uint32_t entry = adiv5_mem_read32(ap, addr + i*4);
@ -304,15 +302,18 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr)
/* Find the part number in our part list and run the appropriate probe
* routine if applicable.
*/
for (int i = 0; pidr_pn_bits[i].arch != aa_end; i++) {
int i;
for (i = 0; pidr_pn_bits[i].arch != aa_end; i++) {
if (pidr_pn_bits[i].part_number == part_number) {
DEBUG("0x%X: %s %s\n", addr,
DEBUG("0x%X: %s - %s %s\n", addr,
cidc_debug_strings[cid_class],
pidr_pn_bits[i].type,
pidr_pn_bits[i].full);
/* Perform sanity check, if we know what to expect as component ID
* class.
*/
if (cid_class != pidr_pn_bits[i].cidc) {
if ((pidr_pn_bits[i].cidc != cidc_unknown) &&
(cid_class != pidr_pn_bits[i].cidc)) {
DEBUG("WARNING: \"%s\" !match expected \"%s\"\n",
cidc_debug_strings[cid_class],
cidc_debug_strings[pidr_pn_bits[i].cidc]);
@ -327,11 +328,15 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr)
cortexa_probe(ap, addr);
break;
default:
DEBUG("-> skip\n");
break;
}
break;
}
}
if (pidr_pn_bits[i].arch == aa_end) {
DEBUG("0x%X: %s - Unknown (PIDR = 0x%"PRIx64")\n", addr,
cidc_debug_strings[cid_class], pidr);
}
}
}
@ -368,11 +373,11 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel)
~(ADIV5_AP_CSW_SIZE_MASK | ADIV5_AP_CSW_ADDRINC_MASK);
if (ap->csw & ADIV5_AP_CSW_TRINPROG) {
gdb_out("AP transaction in progress. Target may not be usable.\n");
DEBUG("AP transaction in progress. Target may not be usable.\n");
ap->csw &= ~ADIV5_AP_CSW_TRINPROG;
}
DEBUG("%3d: IDR=%08X CFG=%08X BASE=%08X CSW=%08X\n",
DEBUG(" AP %3d: IDR=%08X CFG=%08X BASE=%08X CSW=%08X\n",
apsel, ap->idr, ap->cfg, ap->base, ap->csw);
return ap;
@ -390,7 +395,7 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
}
if (e.type) {
gdb_out("DP not responding! Trying abort sequence...\n");
DEBUG("DP not responding! Trying abort sequence...\n");
adiv5_dp_abort(dp, ADIV5_DP_ABORT_DAPABORT);
ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
}
@ -499,6 +504,9 @@ adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
uint32_t osrc = src;
enum align align = MIN(ALIGNOF(src), ALIGNOF(len));
if (len == 0)
return;
len >>= align;
ap_mem_access_setup(ap, src, align);
adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_AP_DRW, 0);

View File

@ -164,7 +164,6 @@ void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr);
void adiv5_jtag_dp_handler(jtag_dev_t *dev);
int adiv5_swdp_scan(void);
void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len);
void adiv5_mem_write(ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len);

View File

@ -26,10 +26,8 @@
#include "exception.h"
#include "adiv5.h"
#include "swdptap.h"
#include "jtagtap.h"
#include "command.h"
#include "morse.h"
#include "gdb_packet.h"
#include "target.h"
#include "target_internal.h"
#define SWDP_ACK_OK 0x01
#define SWDP_ACK_WAIT 0x02
@ -52,6 +50,16 @@ int adiv5_swdp_scan(void)
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
swdptap_init();
/* Switch from JTAG to SWD mode */
swdptap_seq_out(0xFFFF, 16);
for(int i = 0; i < 50; i++)
swdptap_bit_out(1);
swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
for(int i = 0; i < 50; i++)
swdptap_bit_out(1);
swdptap_seq_out(0, 16);
/* Read the SW-DP IDCODE register to syncronise */
/* This could be done with adiv_swdp_low_access(), but this doesn't
* allow the ack to be checked here. */
@ -59,7 +67,6 @@ int adiv5_swdp_scan(void)
ack = swdptap_seq_in(3);
if((ack != SWDP_ACK_OK) || swdptap_seq_in_parity(&dp->idcode, 32)) {
DEBUG("\n");
morse("NO TARGETS.", 1);
free(dp);
return -1;
}
@ -72,9 +79,6 @@ int adiv5_swdp_scan(void)
adiv5_swdp_error(dp);
adiv5_dp_init(dp);
if(!target_list) morse("NO TARGETS.", 1);
else morse(NULL, 0);
return target_list?1:0;
}

View File

@ -29,25 +29,12 @@
*/
#include "general.h"
#include "exception.h"
#include "jtagtap.h"
#include "jtag_scan.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "cortexm.h"
#include "morse.h"
#include <unistd.h>
#include "target_internal.h"
static char cortexa_driver_str[] = "ARM Cortex-A";
/* Signals returned by cortexa_halt_wait() */
#define SIGINT 2
#define SIGTRAP 5
#define SIGSEGV 11
#define SIGLOST 29
static bool cortexa_attach(target *t);
static void cortexa_detach(target *t);
static void cortexa_halt_resume(target *t, bool step);
@ -58,11 +45,11 @@ static void cortexa_regs_read_internal(target *t);
static void cortexa_regs_write_internal(target *t);
static void cortexa_reset(target *t);
static int cortexa_halt_wait(target *t);
static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch);
static void cortexa_halt_request(target *t);
static int cortexa_set_hw_bp(target *t, uint32_t addr, uint8_t len);
static int cortexa_clear_hw_bp(target *t, uint32_t addr, uint8_t len);
static int cortexa_breakwatch_set(target *t, struct breakwatch *);
static int cortexa_breakwatch_clear(target *t, struct breakwatch *);
static uint32_t bp_bas(uint32_t addr, uint8_t len);
static void apb_write(target *t, uint16_t reg, uint32_t val);
@ -81,7 +68,7 @@ struct cortexa_priv {
uint64_t d[16];
} reg_cache;
unsigned hw_breakpoint_max;
unsigned hw_breakpoint[16];
bool hw_breakpoint[16];
uint32_t bpc0;
bool mmu_fault;
};
@ -228,7 +215,7 @@ static uint32_t va_to_pa(target *t, uint32_t va)
return pa;
}
static void cortexa_mem_read(target *t, void *dest, uint32_t src, size_t len)
static void cortexa_mem_read(target *t, void *dest, target_addr src, size_t len)
{
/* Clean cache before reading */
for (uint32_t cl = src & ~(CACHE_LINE_LENGTH-1);
@ -241,7 +228,7 @@ static void cortexa_mem_read(target *t, void *dest, uint32_t src, size_t len)
adiv5_mem_read(ahb, dest, va_to_pa(t, src), len);
}
static void cortexa_slow_mem_read(target *t, void *dest, uint32_t src, size_t len)
static void cortexa_slow_mem_read(target *t, void *dest, target_addr src, size_t len)
{
struct cortexa_priv *priv = t->priv;
unsigned words = (len + (src & 3) + 3) / 4;
@ -280,7 +267,7 @@ static void cortexa_slow_mem_read(target *t, void *dest, uint32_t src, size_t le
}
}
static void cortexa_mem_write(target *t, uint32_t dest, const void *src, size_t len)
static void cortexa_mem_write(target *t, target_addr dest, const void *src, size_t len)
{
/* Clean and invalidate cache before writing */
for (uint32_t cl = dest & ~(CACHE_LINE_LENGTH-1);
@ -292,7 +279,7 @@ static void cortexa_mem_write(target *t, uint32_t dest, const void *src, size_t
adiv5_mem_write(ahb, va_to_pa(t, dest), src, len);
}
static void cortexa_slow_mem_write_bytes(target *t, uint32_t dest, const uint8_t *src, size_t len)
static void cortexa_slow_mem_write_bytes(target *t, target_addr dest, const uint8_t *src, size_t len)
{
struct cortexa_priv *priv = t->priv;
@ -311,7 +298,7 @@ static void cortexa_slow_mem_write_bytes(target *t, uint32_t dest, const uint8_t
}
}
static void cortexa_slow_mem_write(target *t, uint32_t dest, const void *src, size_t len)
static void cortexa_slow_mem_write(target *t, target_addr dest, const void *src, size_t len)
{
struct cortexa_priv *priv = t->priv;
if (len == 0)
@ -360,10 +347,7 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base)
{
target *t;
DEBUG("%s base=0x%08"PRIx32"\n", __func__, debug_base);
/* Prepend to target list... */
t = target_new(sizeof(*t));
t = target_new();
adiv5_ap_ref(apb);
struct cortexa_priv *priv = calloc(1, sizeof(*priv));
t->priv = priv;
@ -391,7 +375,6 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base)
adiv5_ap_write(apb, ADIV5_AP_CSW, csw);
uint32_t dbgdidr = apb_read(t, DBGDIDR);
priv->hw_breakpoint_max = ((dbgdidr >> 24) & 15)+1;
DEBUG("Target has %d breakpoints\n", priv->hw_breakpoint_max);
t->check_error = cortexa_check_error;
@ -406,12 +389,12 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base)
t->reset = cortexa_reset;
t->halt_request = cortexa_halt_request;
t->halt_wait = cortexa_halt_wait;
t->halt_poll = cortexa_halt_poll;
t->halt_resume = cortexa_halt_resume;
t->regs_size = sizeof(priv->reg_cache);
t->set_hw_bp = cortexa_set_hw_bp;
t->clear_hw_bp = cortexa_clear_hw_bp;
t->breakwatch_set = cortexa_breakwatch_set;
t->breakwatch_clear = cortexa_breakwatch_clear;
return true;
}
@ -433,7 +416,7 @@ bool cortexa_attach(target *t)
target_halt_request(t);
tries = 10;
while(!platform_srst_get_val() && !target_halt_wait(t) && --tries)
while(!platform_srst_get_val() && !target_halt_poll(t, NULL) && --tries)
platform_delay(200);
if(!tries)
return false;
@ -593,12 +576,14 @@ static void cortexa_halt_request(target *t)
apb_write(t, DBGDRCR, DBGDRCR_HRQ);
}
if (e.type) {
gdb_out("Timeout sending interrupt, is target in WFI?\n");
tc_printf(t, "Timeout sending interrupt, is target in WFI?\n");
}
}
static int cortexa_halt_wait(target *t)
static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch)
{
(void)watch; /* No watchpoint support yet */
volatile uint32_t dbgdscr = 0;
volatile struct exception e;
TRY_CATCH (e, EXCEPTION_ALL) {
@ -610,15 +595,14 @@ static int cortexa_halt_wait(target *t)
case EXCEPTION_ERROR:
/* Oh crap, there's no recovery from this... */
target_list_free();
morse("TARGET LOST.", 1);
return SIGLOST;
return TARGET_HALT_ERROR;
case EXCEPTION_TIMEOUT:
/* Timeout isn't a problem, target could be in WFI */
return 0;
return TARGET_HALT_RUNNING;
}
if (!(dbgdscr & DBGDSCR_HALTED)) /* Not halted */
return 0;
return TARGET_HALT_RUNNING;
DEBUG("%s: DBGDSCR = 0x%08x\n", __func__, dbgdscr);
/* Reenable DBGITR */
@ -626,18 +610,18 @@ static int cortexa_halt_wait(target *t)
apb_write(t, DBGDSCR, dbgdscr);
/* Find out why we halted */
int sig;
enum target_halt_reason reason;
switch (dbgdscr & DBGDSCR_MOE_MASK) {
case DBGDSCR_MOE_HALT_REQ:
sig = SIGINT;
reason = TARGET_HALT_REQUEST;
break;
default:
sig = SIGTRAP;
reason = TARGET_HALT_BREAKPOINT;
}
cortexa_regs_read_internal(t);
return sig;
return reason;
}
void cortexa_halt_resume(target *t, bool step)
@ -689,45 +673,75 @@ static uint32_t bp_bas(uint32_t addr, uint8_t len)
return DBGBCR_BAS_LOW_HW;
}
static int cortexa_set_hw_bp(target *t, uint32_t addr, uint8_t len)
static int cortexa_breakwatch_set(target *t, struct breakwatch *bw)
{
struct cortexa_priv *priv = t->priv;
unsigned i;
for(i = 0; i < priv->hw_breakpoint_max; i++)
if((priv->hw_breakpoint[i] & 1) == 0) break;
switch (bw->type) {
case TARGET_BREAK_SOFT:
switch (bw->size) {
case 2:
bw->reserved[0] = target_mem_read16(t, bw->addr);
target_mem_write16(t, bw->addr, 0xBE00);
return 0;
case 4:
bw->reserved[0] = target_mem_read32(t, bw->addr);
target_mem_write32(t, bw->addr, 0xE1200070);
return 0;
default:
return -1;
}
case TARGET_BREAK_HARD:
if ((bw->size != 4) && (bw->size != 2))
return -1;
if(i == priv->hw_breakpoint_max) return -1;
for (i = 0; i < priv->hw_breakpoint_max; i++)
if ((priv->hw_breakpoint[i] & 1) == 0)
break;
priv->hw_breakpoint[i] = addr | 1;
if (i == priv->hw_breakpoint_max)
return -1;
apb_write(t, DBGBVR(i), addr & ~3);
uint32_t bpc = bp_bas(addr, len) | DBGBCR_EN;
apb_write(t, DBGBCR(i), bpc);
if (i == 0)
priv->bpc0 = bpc;
bw->reserved[0] = i;
return 0;
priv->hw_breakpoint[i] = true;
apb_write(t, DBGBVR(i), bw->addr & ~3);
uint32_t bpc = bp_bas(bw->addr, bw->size) | DBGBCR_EN;
apb_write(t, DBGBCR(i), bpc);
if (i == 0)
priv->bpc0 = bpc;
return 0;
default:
return 1;
}
}
static int cortexa_clear_hw_bp(target *t, uint32_t addr, uint8_t len)
static int cortexa_breakwatch_clear(target *t, struct breakwatch *bw)
{
struct cortexa_priv *priv = t->priv;
unsigned i;
(void)len;
for (i = 0; i < priv->hw_breakpoint_max; i++)
if ((priv->hw_breakpoint[i] & ~1) == addr)
break;
if (i == priv->hw_breakpoint_max)
return -1;
priv->hw_breakpoint[i] = 0;
apb_write(t, DBGBCR(i), 0);
if (i == 0)
priv->bpc0 = 0;
return 0;
unsigned i = bw->reserved[0];
switch (bw->type) {
case TARGET_BREAK_SOFT:
switch (bw->size) {
case 2:
target_mem_write16(t, bw->addr, i);
return 0;
case 4:
target_mem_write32(t, bw->addr, i);
return 0;
default:
return -1;
}
case TARGET_BREAK_HARD:
priv->hw_breakpoint[i] = false;
apb_write(t, DBGBCR(i), 0);
if (i == 0)
priv->bpc0 = 0;
return 0;
default:
return 1;
}
}

View File

@ -29,16 +29,11 @@
#include "exception.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include "cortexm.h"
#include "morse.h"
#include <unistd.h>
/* On some systems this is a macro and causes problems */
#undef errno
static char cortexm_driver_str[] = "ARM Cortex-M";
static bool cortexm_vector_catch(target *t, int argc, char *argv[]);
@ -52,56 +47,37 @@ const struct command_s cortexm_cmd_list[] = {
#define TOPT_FLAVOUR_V6M (1<<0) /* if not set, target is assumed to be v7m */
#define TOPT_FLAVOUR_V7MF (1<<1) /* if set, floating-point enabled. */
/* Signals returned by cortexm_halt_wait() */
#define SIGINT 2
#define SIGTRAP 5
#define SIGSEGV 11
#define SIGLOST 29
static void cortexm_regs_read(target *t, void *data);
static void cortexm_regs_write(target *t, const void *data);
static uint32_t cortexm_pc_read(target *t);
static void cortexm_reset(target *t);
static int cortexm_halt_wait(target *t);
static enum target_halt_reason cortexm_halt_poll(target *t, target_addr *watch);
static void cortexm_halt_request(target *t);
static int cortexm_fault_unwind(target *t);
static int cortexm_set_hw_bp(target *t, uint32_t addr, uint8_t len);
static int cortexm_clear_hw_bp(target *t, uint32_t addr, uint8_t len);
static int cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len);
static int cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len);
static int cortexm_check_hw_wp(target *t, uint32_t *addr);
static int cortexm_breakwatch_set(target *t, struct breakwatch *);
static int cortexm_breakwatch_clear(target *t, struct breakwatch *);
static target_addr cortexm_check_watch(target *t);
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
#define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */
static int cortexm_hostio_request(target *t);
static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode);
struct cortexm_priv {
ADIv5_AP_t *ap;
bool stepping;
bool on_bkpt;
/* Watchpoint unit status */
struct wp_unit_s {
uint32_t addr;
uint8_t type;
uint8_t size;
} hw_watchpoint[CORTEXM_MAX_WATCHPOINTS];
bool hw_watchpoint[CORTEXM_MAX_WATCHPOINTS];
unsigned flash_patch_revision;
unsigned hw_watchpoint_max;
/* Breakpoint unit status */
uint32_t hw_breakpoint[CORTEXM_MAX_BREAKPOINTS];
bool hw_breakpoint[CORTEXM_MAX_BREAKPOINTS];
unsigned hw_breakpoint_max;
/* Copy of DEMCR for vector-catch */
uint32_t demcr;
/* Semihosting state */
uint32_t syscall;
uint32_t errno;
uint32_t byte_count;
};
/* Register number tables */
@ -203,12 +179,12 @@ ADIv5_AP_t *cortexm_ap(target *t)
return ((struct cortexm_priv *)t->priv)->ap;
}
static void cortexm_mem_read(target *t, void *dest, uint32_t src, size_t len)
static void cortexm_mem_read(target *t, void *dest, target_addr src, size_t len)
{
adiv5_mem_read(cortexm_ap(t), dest, src, len);
}
static void cortexm_mem_write(target *t, uint32_t dest, const void *src, size_t len)
static void cortexm_mem_write(target *t, target_addr dest, const void *src, size_t len)
{
adiv5_mem_write(cortexm_ap(t), dest, src, len);
}
@ -229,7 +205,7 @@ bool cortexm_probe(ADIv5_AP_t *ap)
{
target *t;
t = target_new(sizeof(*t));
t = target_new();
adiv5_ap_ref(ap);
struct cortexm_priv *priv = calloc(1, sizeof(*priv));
t->priv = priv;
@ -252,11 +228,12 @@ bool cortexm_probe(ADIv5_AP_t *ap)
t->reset = cortexm_reset;
t->halt_request = cortexm_halt_request;
t->halt_wait = cortexm_halt_wait;
t->halt_poll = cortexm_halt_poll;
t->halt_resume = cortexm_halt_resume;
t->regs_size = sizeof(regnum_cortex_m);
t->hostio_reply = cortexm_hostio_reply;
t->breakwatch_set = cortexm_breakwatch_set;
t->breakwatch_clear = cortexm_breakwatch_clear;
target_add_commands(t, cortexm_cmd_list, cortexm_driver_str);
@ -307,7 +284,7 @@ bool cortexm_attach(target *t)
target_halt_request(t);
tries = 10;
while(!platform_srst_get_val() && !target_halt_wait(t) && --tries)
while(!platform_srst_get_val() && !target_halt_poll(t, NULL) && --tries)
platform_delay(200);
if(!tries)
return false;
@ -338,19 +315,12 @@ bool cortexm_attach(target *t)
/* Clear any stale watchpoints */
for(i = 0; i < priv->hw_watchpoint_max; i++) {
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
priv->hw_watchpoint[i].type = 0;
priv->hw_watchpoint[i] = 0;
}
/* Flash Patch Control Register: set ENABLE */
target_mem_write32(t, CORTEXM_FPB_CTRL,
CORTEXM_FPB_CTRL_KEY | CORTEXM_FPB_CTRL_ENABLE);
t->set_hw_bp = cortexm_set_hw_bp;
t->clear_hw_bp = cortexm_clear_hw_bp;
/* Data Watchpoint and Trace */
t->set_hw_wp = cortexm_set_hw_wp;
t->clear_hw_wp = cortexm_clear_hw_wp;
t->check_hw_wp = cortexm_check_hw_wp;
platform_srst_set_val(false);
@ -488,11 +458,11 @@ static void cortexm_halt_request(target *t)
CORTEXM_DHCSR_C_DEBUGEN);
}
if (e.type) {
gdb_out("Timeout sending interrupt, is target in WFI?\n");
tc_printf(t, "Timeout sending interrupt, is target in WFI?\n");
}
}
static int cortexm_halt_wait(target *t)
static enum target_halt_reason cortexm_halt_poll(target *t, target_addr *watch)
{
struct cortexm_priv *priv = t->priv;
@ -507,22 +477,21 @@ static int cortexm_halt_wait(target *t)
case EXCEPTION_ERROR:
/* Oh crap, there's no recovery from this... */
target_list_free();
morse("TARGET LOST.", 1);
return SIGLOST;
return TARGET_HALT_ERROR;
case EXCEPTION_TIMEOUT:
/* Timeout isn't a problem, target could be in WFI */
return 0;
return TARGET_HALT_RUNNING;
}
if (!(dhcsr & CORTEXM_DHCSR_S_HALT))
return 0;
return TARGET_HALT_RUNNING;
/* We've halted. Let's find out why. */
uint32_t dfsr = target_mem_read32(t, CORTEXM_DFSR);
target_mem_write32(t, CORTEXM_DFSR, dfsr); /* write back to reset */
if ((dfsr & CORTEXM_DFSR_VCATCH) && cortexm_fault_unwind(t))
return SIGSEGV;
return TARGET_HALT_FAULT;
/* Remember if we stopped on a breakpoint */
priv->on_bkpt = dfsr & (CORTEXM_DFSR_BKPT);
@ -533,24 +502,27 @@ static int cortexm_halt_wait(target *t)
uint16_t bkpt_instr;
bkpt_instr = target_mem_read16(t, pc);
if (bkpt_instr == 0xBEAB) {
int n = cortexm_hostio_request(t);
if (n > 0) {
if (cortexm_hostio_request(t)) {
return TARGET_HALT_REQUEST;
} else {
target_halt_resume(t, priv->stepping);
return 0;
} else if (n < 0) {
return -1;
}
}
}
if (dfsr & (CORTEXM_DFSR_BKPT | CORTEXM_DFSR_DWTTRAP))
return SIGTRAP;
if (dfsr & CORTEXM_DFSR_DWTTRAP) {
if (watch != NULL)
*watch = cortexm_check_watch(t);
return TARGET_HALT_WATCHPOINT;
}
if (dfsr & CORTEXM_DFSR_BKPT)
return TARGET_HALT_BREAKPOINT;
if (dfsr & CORTEXM_DFSR_HALTED)
return priv->stepping ? SIGTRAP : SIGINT;
return SIGTRAP;
return priv->stepping ? TARGET_HALT_STEPPING : TARGET_HALT_REQUEST;
return TARGET_HALT_BREAKPOINT;
}
void cortexm_halt_resume(target *t, bool step)
@ -656,7 +628,7 @@ int cortexm_run_stub(target *t, uint32_t loadaddr,
/* Execute the stub */
cortexm_halt_resume(t, 0);
while (!cortexm_halt_wait(t))
while (!cortexm_halt_poll(t, NULL))
;
uint32_t pc = cortexm_pc_read(t);
@ -667,148 +639,128 @@ int cortexm_run_stub(target *t, uint32_t loadaddr,
return bkpt_instr & 0xff;
}
/* The following routines implement hardware breakpoints.
* The Flash Patch and Breakpoint (FPB) system is used. */
/* The following routines implement hardware breakpoints and watchpoints.
* The Flash Patch and Breakpoint (FPB) and Data Watch and Trace (DWT)
* systems are used. */
static int cortexm_set_hw_bp(target *t, uint32_t addr, uint8_t len)
static uint32_t dwt_mask(size_t len)
{
(void)len;
struct cortexm_priv *priv = t->priv;
uint32_t val = addr;
unsigned i;
if (priv->flash_patch_revision == 0) {
val = addr & 0x1FFFFFFC;
val |= (addr & 2)?0x80000000:0x40000000;
switch (len) {
case 1:
return CORTEXM_DWT_MASK_BYTE;
case 2:
return CORTEXM_DWT_MASK_HALFWORD;
case 4:
return CORTEXM_DWT_MASK_WORD;
default:
return -1;
}
val |= 1;
for(i = 0; i < priv->hw_breakpoint_max; i++)
if((priv->hw_breakpoint[i] & 1) == 0) break;
if(i == priv->hw_breakpoint_max) return -1;
priv->hw_breakpoint[i] = addr | 1;
target_mem_write32(t, CORTEXM_FPB_COMP(i), val);
return 0;
}
static int cortexm_clear_hw_bp(target *t, uint32_t addr, uint8_t len)
static uint32_t dwt_func(target *t, enum target_breakwatch type)
{
(void)len;
struct cortexm_priv *priv = t->priv;
unsigned i;
uint32_t x = 0;
for(i = 0; i < priv->hw_breakpoint_max; i++)
if((priv->hw_breakpoint[i] & ~1) == addr) break;
if ((t->target_options & TOPT_FLAVOUR_V6M) == 0)
x = CORTEXM_DWT_FUNC_DATAVSIZE_WORD;
if(i == priv->hw_breakpoint_max) return -1;
priv->hw_breakpoint[i] = 0;
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
return 0;
switch (type) {
case TARGET_WATCH_WRITE:
return CORTEXM_DWT_FUNC_FUNC_WRITE | x;
case TARGET_WATCH_READ:
return CORTEXM_DWT_FUNC_FUNC_READ | x;
case TARGET_WATCH_ACCESS:
return CORTEXM_DWT_FUNC_FUNC_ACCESS | x;
default:
return -1;
}
}
/* The following routines implement hardware watchpoints.
* The Data Watch and Trace (DWT) system is used. */
static int
cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len)
static int cortexm_breakwatch_set(target *t, struct breakwatch *bw)
{
struct cortexm_priv *priv = t->priv;
unsigned i;
uint32_t val = bw->addr;
switch(len) { /* Convert bytes size to mask size */
case 1: len = CORTEXM_DWT_MASK_BYTE; break;
case 2: len = CORTEXM_DWT_MASK_HALFWORD; break;
case 4: len = CORTEXM_DWT_MASK_WORD; break;
default:
switch (bw->type) {
case TARGET_BREAK_HARD:
if (priv->flash_patch_revision == 0) {
val &= 0x1FFFFFFC;
val |= (bw->addr & 2)?0x80000000:0x40000000;
}
val |= 1;
for(i = 0; i < priv->hw_breakpoint_max; i++)
if (!priv->hw_breakpoint[i])
break;
if (i == priv->hw_breakpoint_max)
return -1;
}
switch(type) { /* Convert gdb type to function type */
case 2: type = CORTEXM_DWT_FUNC_FUNC_WRITE; break;
case 3: type = CORTEXM_DWT_FUNC_FUNC_READ; break;
case 4: type = CORTEXM_DWT_FUNC_FUNC_ACCESS; break;
default:
priv->hw_breakpoint[i] = true;
target_mem_write32(t, CORTEXM_FPB_COMP(i), val);
bw->reserved[0] = i;
return 0;
case TARGET_WATCH_WRITE:
case TARGET_WATCH_READ:
case TARGET_WATCH_ACCESS:
for(i = 0; i < priv->hw_watchpoint_max; i++)
if (!priv->hw_watchpoint[i])
break;
if (i == priv->hw_watchpoint_max)
return -1;
priv->hw_watchpoint[i] = true;
target_mem_write32(t, CORTEXM_DWT_COMP(i), val);
target_mem_write32(t, CORTEXM_DWT_MASK(i), dwt_mask(bw->size));
target_mem_write32(t, CORTEXM_DWT_FUNC(i), dwt_func(t, bw->type));
bw->reserved[0] = i;
return 0;
default:
return 1;
}
for(i = 0; i < priv->hw_watchpoint_max; i++)
if((priv->hw_watchpoint[i].type == 0) &&
((target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & 0xF) == 0))
break;
if(i == priv->hw_watchpoint_max) return -2;
priv->hw_watchpoint[i].type = type;
priv->hw_watchpoint[i].addr = addr;
priv->hw_watchpoint[i].size = len;
target_mem_write32(t, CORTEXM_DWT_COMP(i), addr);
target_mem_write32(t, CORTEXM_DWT_MASK(i), len);
target_mem_write32(t, CORTEXM_DWT_FUNC(i), type |
((t->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD));
return 0;
}
static int
cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len)
static int cortexm_breakwatch_clear(target *t, struct breakwatch *bw)
{
struct cortexm_priv *priv = t->priv;
unsigned i;
switch(len) {
case 1: len = CORTEXM_DWT_MASK_BYTE; break;
case 2: len = CORTEXM_DWT_MASK_HALFWORD; break;
case 4: len = CORTEXM_DWT_MASK_WORD; break;
default:
return -1;
unsigned i = bw->reserved[0];
switch (bw->type) {
case TARGET_BREAK_HARD:
priv->hw_breakpoint[i] = false;
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
return 0;
case TARGET_WATCH_WRITE:
case TARGET_WATCH_READ:
case TARGET_WATCH_ACCESS:
priv->hw_watchpoint[i] = false;
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
return 0;
default:
return 1;
}
switch(type) {
case 2: type = CORTEXM_DWT_FUNC_FUNC_WRITE; break;
case 3: type = CORTEXM_DWT_FUNC_FUNC_READ; break;
case 4: type = CORTEXM_DWT_FUNC_FUNC_ACCESS; break;
default:
return -1;
}
for(i = 0; i < priv->hw_watchpoint_max; i++)
if((priv->hw_watchpoint[i].addr == addr) &&
(priv->hw_watchpoint[i].type == type) &&
(priv->hw_watchpoint[i].size == len)) break;
if(i == priv->hw_watchpoint_max) return -2;
priv->hw_watchpoint[i].type = 0;
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
return 0;
}
static int cortexm_check_hw_wp(target *t, uint32_t *addr)
static target_addr cortexm_check_watch(target *t)
{
struct cortexm_priv *priv = t->priv;
unsigned i;
for(i = 0; i < priv->hw_watchpoint_max; i++)
/* if SET and MATCHED then break */
if(priv->hw_watchpoint[i].type &&
if(priv->hw_watchpoint[i] &&
(target_mem_read32(t, CORTEXM_DWT_FUNC(i)) &
CORTEXM_DWT_FUNC_MATCHED))
break;
if(i == priv->hw_watchpoint_max) return 0;
if (i == priv->hw_watchpoint_max)
return 0;
*addr = priv->hw_watchpoint[i].addr;
return 1;
return target_mem_read32(t, CORTEXM_DWT_COMP(i));
}
static bool cortexm_vector_catch(target *t, int argc, char *argv[])
@ -820,8 +772,8 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
unsigned i;
if ((argc < 3) || ((argv[1][0] != 'e') && (argv[1][0] != 'd'))) {
gdb_out("usage: monitor vector_catch (enable|disable) "
"(hard|int|bus|stat|chk|nocp|mm|reset)\n");
tc_printf(t, "usage: monitor vector_catch (enable|disable) "
"(hard|int|bus|stat|chk|nocp|mm|reset)\n");
} else {
for (int j = 0; j < argc; j++)
for (i = 0; i < sizeof(vectors) / sizeof(char*); i++) {
@ -837,14 +789,14 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
target_mem_write32(t, CORTEXM_DEMCR, priv->demcr);
}
gdb_out("Catching vectors: ");
tc_printf(t, "Catching vectors: ");
for (i = 0; i < sizeof(vectors) / sizeof(char*); i++) {
if (!vectors[i])
continue;
if (priv->demcr & (1 << i))
gdb_outf("%s ", vectors[i]);
tc_printf(t, "%s ", vectors[i]);
}
gdb_out("\n");
tc_printf(t, "\n");
return true;
}
@ -878,40 +830,30 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
#define SYS_WRITEC 0x03
#define SYS_WRITE0 0x04
#define FILEIO_O_RDONLY 0
#define FILEIO_O_WRONLY 1
#define FILEIO_O_RDWR 2
#define FILEIO_O_APPEND 0x008
#define FILEIO_O_CREAT 0x200
#define FILEIO_O_TRUNC 0x400
#define FILEIO_SEEK_SET 0
#define FILEIO_SEEK_CUR 1
#define FILEIO_SEEK_END 2
static int cortexm_hostio_request(target *t)
{
struct cortexm_priv *priv = t->priv;
uint32_t arm_regs[t->regs_size];
uint32_t params[4];
t->tc->interrupted = false;
target_regs_read(t, arm_regs);
target_mem_read(t, params, arm_regs[1], sizeof(params));
priv->syscall = arm_regs[0];
uint32_t syscall = arm_regs[0];
int32_t ret = 0;
DEBUG("syscall 0x%x (%x %x %x %x)\n", priv->syscall,
DEBUG("syscall 0x%x (%x %x %x %x)\n", syscall,
params[0], params[1], params[2], params[3]);
switch (priv->syscall) {
switch (syscall) {
case SYS_OPEN:{ /* open */
/* Translate stupid fopen modes to open flags.
* See DUI0471C, Table 8-3 */
const uint32_t flags[] = {
FILEIO_O_RDONLY, /* r, rb */
FILEIO_O_RDWR, /* r+, r+b */
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w*/
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w+*/
FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a*/
FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a+*/
TARGET_O_RDONLY, /* r, rb */
TARGET_O_RDWR, /* r+, r+b */
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,/*w*/
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,/*w+*/
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,/*a*/
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND,/*a+*/
};
uint32_t pflag = flags[params[1] >> 1];
char filename[4];
@ -919,91 +861,70 @@ static int cortexm_hostio_request(target *t)
target_mem_read(t, filename, params[0], sizeof(filename));
/* handle requests for console i/o */
if (!strcmp(filename, ":tt")) {
if (pflag == FILEIO_O_RDONLY)
arm_regs[0] = STDIN_FILENO;
else if (pflag & FILEIO_O_TRUNC)
arm_regs[0] = STDOUT_FILENO;
if (pflag == TARGET_O_RDONLY)
ret = STDIN_FILENO;
else if (pflag & TARGET_O_TRUNC)
ret = STDOUT_FILENO;
else
arm_regs[0] = STDERR_FILENO;
arm_regs[0]++;
target_regs_write(t, arm_regs);
return 1;
ret = STDERR_FILENO;
ret++;
break;
}
gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X",
params[0], params[2] + 1,
pflag, 0644);
ret = tc_open(t, params[0], params[2] + 1, pflag, 0644);
if (ret != -1)
ret++;
break;
}
case SYS_CLOSE: /* close */
gdb_putpacket_f("Fclose,%08X", params[0] - 1);
ret = tc_close(t, params[0] - 1);
break;
case SYS_READ: /* read */
priv->byte_count = params[2];
gdb_putpacket_f("Fread,%08X,%08X,%08X",
params[0] - 1, params[1], params[2]);
ret = tc_read(t, params[0] - 1, params[1], params[2]);
if (ret > 0)
ret = params[2] - ret;
break;
case SYS_WRITE: /* write */
priv->byte_count = params[2];
gdb_putpacket_f("Fwrite,%08X,%08X,%08X",
params[0] - 1, params[1], params[2]);
ret = tc_write(t, params[0] - 1, params[1], params[2]);
if (ret > 0)
ret = params[2] - ret;
break;
case SYS_WRITEC: /* writec */
gdb_putpacket_f("Fwrite,2,%08X,1", arm_regs[1]);
ret = tc_write(t, 2, arm_regs[1], 1);
break;
case SYS_ISTTY: /* isatty */
gdb_putpacket_f("Fisatty,%08X", params[0] - 1);
ret = tc_isatty(t, params[0] - 1);
break;
case SYS_SEEK: /* lseek */
gdb_putpacket_f("Flseek,%08X,%08X,%08X",
params[0] - 1, params[1], FILEIO_SEEK_SET);
ret = tc_lseek(t, params[0] - 1, params[1], TARGET_SEEK_SET);
break;
case SYS_RENAME:/* rename */
gdb_putpacket_f("Frename,%08X/%X,%08X/%X",
params[0] - 1, params[1] + 1,
ret = tc_rename(t, params[0] - 1, params[1] + 1,
params[2], params[3] + 1);
break;
case SYS_REMOVE:/* unlink */
gdb_putpacket_f("Funlink,%08X/%X", params[0] - 1,
params[1] + 1);
ret = tc_unlink(t, params[0] - 1, params[1] + 1);
break;
case SYS_SYSTEM:/* system */
gdb_putpacket_f("Fsystem,%08X/%X", params[0] - 1,
params[1] + 1);
ret = tc_system(t, params[0] - 1, params[1] + 1);
break;
case SYS_FLEN: /* Not supported, fake success */
priv->errno = 0;
return 1;
t->tc->errno_ = 0;
break;
case SYS_ERRNO: /* Return last errno from GDB */
arm_regs[0] = priv->errno;
target_regs_write(t, arm_regs);
return 1;
ret = t->tc->errno_;
break;
case SYS_TIME: /* gettimeofday */
/* FIXME How do we use gdb's gettimeofday? */
default:
return 0;
break;
}
return -1;
}
static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode)
{
struct cortexm_priv *priv = t->priv;
uint32_t arm_regs[t->regs_size];
DEBUG("syscall return ret=%d errno=%d\n", retcode, errcode);
target_regs_read(t, arm_regs);
if (((priv->syscall == SYS_READ) || (priv->syscall == SYS_WRITE)) &&
(retcode > 0))
retcode = priv->byte_count - retcode;
if ((priv->syscall == SYS_OPEN) && (retcode != -1))
retcode++;
arm_regs[0] = retcode;
arm_regs[0] = ret;
target_regs_write(t, arm_regs);
priv->errno = errcode;
return t->tc->interrupted;
}

View File

@ -37,22 +37,19 @@
*/
#include "general.h"
#include "jtagtap.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include "cortexm.h"
#define SRAM_BASE 0x20000000
#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(efm32_flash_write_stub), 4)
static int efm32_flash_erase(struct target_flash *t, uint32_t addr, size_t len);
static int efm32_flash_erase(struct target_flash *t, target_addr addr, size_t len);
static int efm32_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static const uint16_t efm32_flash_write_stub[] = {
#include "../flashstub/efm32.stub"
#include "flashstub/efm32.stub"
};
static bool efm32_cmd_erase_all(target *t);
@ -233,7 +230,7 @@ uint16_t efm32_read_radio_part_number(target *t)
static void efm32_add_flash(target *t, uint32_t addr, size_t length,
static void efm32_add_flash(target *t, target_addr addr, size_t length,
size_t page_size)
{
struct target_flash *f = calloc(1, sizeof(*f));
@ -336,7 +333,7 @@ bool efm32_probe(target *t)
/* Setup Target */
t->target_options |= CORTEXM_TOPT_INHIBIT_SRST;
t->driver = variant_string;
gdb_outf("flash size %d page size %d\n", flash_size, flash_page_size);
tc_printf(t, "flash size %d page size %d\n", flash_size, flash_page_size);
target_add_ram (t, SRAM_BASE, ram_size);
efm32_add_flash(t, 0x00000000, flash_size, flash_page_size);
target_add_commands(t, efm32_cmd_list, "EFM32");
@ -347,7 +344,7 @@ bool efm32_probe(target *t)
/**
* Erase flash row by row
*/
static int efm32_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int efm32_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
@ -379,7 +376,7 @@ static int efm32_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
* Write flash page by page
*/
static int efm32_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
(void)len;
target *t = f->t;
@ -418,7 +415,7 @@ static bool efm32_cmd_erase_all(target *t)
/* Relock mass erase */
target_mem_write32(t, EFM32_MSC_MASSLOCK, 0);
gdb_outf("Erase successful!\n");
tc_printf(t, "Erase successful!\n");
return true;
}
@ -432,7 +429,7 @@ static bool efm32_cmd_serial(target *t)
uint64_t eui = efm32_read_eui(t);
/* 64 bits of unique number */
gdb_outf("Unique Number: 0x%016llx\n", eui);
tc_printf(t, "Unique Number: 0x%016llx\n", eui);
return true;
}

View File

@ -8,7 +8,7 @@ ifneq ($(V), 1)
Q = @
endif
CFLAGS=-Os -std=gnu99 -mcpu=cortex-m0 -mthumb -I../libopencm3/include
CFLAGS=-Os -std=gnu99 -mcpu=cortex-m0 -mthumb -I../../../libopencm3/include
ASFLAGS=-mcpu=cortex-m3 -mthumb
all: lmi.stub stm32f4.stub stm32l4.stub nrf51.stub stm32f1.stub efm32.stub

View File

@ -0,0 +1,13 @@
Flash Stubs
===========
These are simple routines for programming the flash on various Cortex-M
microcontrollers. The routines should be provided with the naked attribute
as the stack may not be available, and must not make any function calls.
The stub must call `stub_exit(code)` provided by `stub.h` to return control
to the debugger. Up to 4 word sized parameters may be taken.
These stubs are compiled instructions comma separated hex values in the
resulting `*.stub` files here, which may be included in the drivers for the
specific device. The drivers call these flash stubs on the target by calling
`cortexm_run_stub` defined in `cortexm.h`.

View File

@ -25,9 +25,7 @@
#include "general.h"
#include "jtagtap.h"
#include "morse.h"
#include "jtag_scan.h"
#include "gdb_packet.h"
#include "target.h"
#include "adiv5.h"
@ -187,7 +185,6 @@ int jtag_scan(const uint8_t *irlens)
jtagtap_next(1, 1);
jtagtap_return_idle();
if(!jtag_dev_count) {
morse("NO TARGETS.", 1);
return 0;
}
@ -224,9 +221,6 @@ int jtag_scan(const uint8_t *irlens)
break;
}
if(!target_list) morse("NO TARGETS.", 1);
else morse(NULL, 0);
return jtag_dev_count;
}

View File

@ -45,8 +45,6 @@ typedef struct jtag_dev_s {
extern struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1];
extern int jtag_dev_count;
int jtag_scan(const uint8_t *lrlens);
void jtag_dev_write_ir(jtag_dev_t *dev, uint32_t ir);
void jtag_dev_shift_dr(jtag_dev_t *dev, uint8_t *dout, const uint8_t *din, int ticks);

View File

@ -21,9 +21,10 @@
/* This file provides generic forms of the low-level jtagtap functions
* for platforms that don't require optimised forms.
*/
#include "general.h"
#include "jtagtap.h"
#ifdef PROVIDE_GENERIC_JTAGTAP_TMS_SEQ
void
void __attribute__((weak))
jtagtap_tms_seq(uint32_t MS, int ticks)
{
while(ticks--) {
@ -31,11 +32,8 @@ jtagtap_tms_seq(uint32_t MS, int ticks)
MS >>= 1;
}
}
#endif
#ifdef PROVIDE_GENERIC_JTAGTAP_TDI_TDO_SEQ
void
void __attribute__((weak))
jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
{
uint8_t index = 1;
@ -51,11 +49,8 @@ jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int
}
}
}
#endif
#ifdef PROVIDE_GENERIC_JTAGTAP_TDI_SEQ
void
void __attribute__((weak))
jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
{
uint8_t index = 1;
@ -67,6 +62,4 @@ jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
}
}
}
#endif

View File

@ -29,6 +29,7 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#define SIM_SDID 0x40048024
@ -60,9 +61,9 @@
#define KL_GEN_PAGESIZE 0x400
static int kl_gen_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int kl_gen_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static void kl_gen_add_flash(target *t,
uint32_t addr, size_t length, size_t erasesize)
@ -158,7 +159,7 @@ kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8])
return true;
}
static int kl_gen_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
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)) {
@ -172,7 +173,7 @@ static int kl_gen_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
}
static int kl_gen_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
while (len) {
if (kl_gen_command(f->t, FTFA_CMD_PROGRAM_LONGWORD, dest, src)) {

View File

@ -26,6 +26,7 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#define SRAM_BASE 0x20000000
@ -46,14 +47,14 @@
#define LMI_FLASH_FMC_COMT (1 << 3)
#define LMI_FLASH_FMC_WRKEY 0xA4420000
static int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int lmi_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int lmi_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static const char lmi_driver_str[] = "TI Stellaris/Tiva";
static const uint16_t lmi_flash_write_stub[] = {
#include "../flashstub/lmi.stub"
#include "flashstub/lmi.stub"
};
static void lmi_add_flash(target *t, size_t length)
@ -88,7 +89,7 @@ bool lmi_probe(target *t)
return false;
}
int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
int lmi_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
while(len) {
@ -105,7 +106,7 @@ int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
}
int lmi_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
target *t = f->t;

View File

@ -20,6 +20,7 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "lpc_common.h"

View File

@ -21,6 +21,7 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "lpc_common.h"

View File

@ -19,9 +19,8 @@
*/
#include "general.h"
#include "command.h"
#include "target.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include "cortexm.h"
#include "lpc_common.h"
@ -51,7 +50,7 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]);
static bool lpc43xx_cmd_reset(target *t, int argc, const char *argv[]);
static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]);
static int lpc43xx_flash_init(target *t);
static int lpc43xx_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int lpc43xx_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static void lpc43xx_set_internal_clock(target *t);
static void lpc43xx_wdt_set_period(target *t);
static void lpc43xx_wdt_pet(target *t);
@ -174,7 +173,7 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[])
return false;
}
gdb_outf("Erase OK.\n");
tc_printf(t, "Erase OK.\n");
return true;
}
@ -195,7 +194,7 @@ static int lpc43xx_flash_init(target *t)
return 0;
}
static int lpc43xx_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int lpc43xx_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
if (lpc43xx_flash_init(f->t))
return -1;
@ -220,14 +219,14 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[])
{
/* Usage: mkboot 0 or mkboot 1 */
if (argc != 2) {
gdb_outf("Expected bank argument 0 or 1.\n");
tc_printf(t, "Expected bank argument 0 or 1.\n");
return false;
}
const long int bank = strtol(argv[1], NULL, 0);
if ((bank != 0) && (bank != 1)) {
gdb_outf("Unexpected bank number, should be 0 or 1.\n");
tc_printf(t, "Unexpected bank number, should be 0 or 1.\n");
return false;
}
@ -236,11 +235,11 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[])
/* special command to compute/write magic vector for signature */
struct lpc_flash *f = (struct lpc_flash *)t->flash;
if (lpc_iap_call(f, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) {
gdb_outf("Set bootable failed.\n");
tc_printf(t, "Set bootable failed.\n");
return false;
}
gdb_outf("Set bootable OK.\n");
tc_printf(t, "Set bootable OK.\n");
return true;
}

View File

@ -18,6 +18,7 @@
*/
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "lpc_common.h"
@ -32,7 +33,7 @@ struct flash_param {
} __attribute__((aligned(4)));
struct lpc_flash *lpc_add_flash(target *t, uint32_t addr, size_t length)
struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length)
{
struct lpc_flash *lf = calloc(1, sizeof(*lf));
struct target_flash *f = &lf->f;
@ -81,7 +82,7 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...)
/* start the target and wait for it to halt again */
target_halt_resume(t, false);
while (!target_halt_wait(t));
while (!target_halt_poll(t, NULL));
/* copy back just the parameters structure */
target_mem_read(t, &param, f->iap_ram, sizeof(param));
@ -93,7 +94,7 @@ static uint8_t lpc_sector_for_addr(struct lpc_flash *f, uint32_t addr)
return f->base_sector + (addr - f->f.start) / f->f.blocksize;
}
int lpc_flash_erase(struct target_flash *tf, uint32_t addr, size_t len)
int lpc_flash_erase(struct target_flash *tf, target_addr addr, size_t len)
{
struct lpc_flash *f = (struct lpc_flash *)tf;
uint32_t start = lpc_sector_for_addr(f, addr);
@ -114,7 +115,7 @@ int lpc_flash_erase(struct target_flash *tf, uint32_t addr, size_t len)
}
int lpc_flash_write(struct target_flash *tf,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
struct lpc_flash *f = (struct lpc_flash *)tf;
/* prepare... */
@ -134,7 +135,7 @@ int lpc_flash_write(struct target_flash *tf,
}
int lpc_flash_write_magic_vect(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
if (dest == 0) {
/* Fill in the magic vector to allow booting the flash */

View File

@ -58,13 +58,13 @@ struct lpc_flash {
uint32_t iap_msp;
};
struct lpc_flash *lpc_add_flash(target *t, uint32_t addr, size_t length);
struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length);
enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...);
int lpc_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
int lpc_flash_erase(struct target_flash *f, target_addr addr, size_t len);
int lpc_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
int lpc_flash_write_magic_vect(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
#endif

View File

@ -22,22 +22,20 @@
*/
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include "cortexm.h"
static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int nrf51_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static bool nrf51_cmd_erase_all(target *t);
static bool nrf51_cmd_read_hwid(target *t);
static bool nrf51_cmd_read_fwid(target *t);
static bool nrf51_cmd_read_deviceid(target *t);
static bool nrf51_cmd_read_deviceaddr(target *t);
static bool nrf51_cmd_read_help(void);
static bool nrf51_cmd_read_help(target *t);
static bool nrf51_cmd_read(target *t, int argc, const char *argv[]);
const struct command_s nrf51_cmd_list[] = {
@ -87,7 +85,7 @@ const struct command_s nrf51_read_cmd_list[] = {
#define STUB_BUFFER_BASE (SRAM_BASE + 0x28)
static const uint16_t nrf51_flash_write_stub[] = {
#include "../flashstub/nrf51.stub"
#include "flashstub/nrf51.stub"
};
static void nrf51_add_flash(target *t,
@ -174,7 +172,7 @@ bool nrf51_probe(target *t)
return false;
}
static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
/* Enable erase */
@ -216,7 +214,7 @@ static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
}
static int nrf51_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
target *t = f->t;
uint32_t data[2 + len/4];
@ -250,7 +248,7 @@ static int nrf51_flash_write(struct target_flash *f,
static bool nrf51_cmd_erase_all(target *t)
{
gdb_out("erase..\n");
tc_printf(t, "erase..\n");
/* Enable erase */
target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN);
@ -274,14 +272,14 @@ static bool nrf51_cmd_erase_all(target *t)
static bool nrf51_cmd_read_hwid(target *t)
{
uint32_t hwid = target_mem_read32(t, NRF51_FICR_CONFIGID) & 0xFFFF;
gdb_outf("Hardware ID: 0x%04X\n", hwid);
tc_printf(t, "Hardware ID: 0x%04X\n", hwid);
return true;
}
static bool nrf51_cmd_read_fwid(target *t)
{
uint32_t fwid = (target_mem_read32(t, NRF51_FICR_CONFIGID) >> 16) & 0xFFFF;
gdb_outf("Firmware ID: 0x%04X\n", fwid);
tc_printf(t, "Firmware ID: 0x%04X\n", fwid);
return true;
}
@ -290,7 +288,7 @@ static bool nrf51_cmd_read_deviceid(target *t)
uint32_t deviceid_low = target_mem_read32(t, NRF51_FICR_DEVICEID_LOW);
uint32_t deviceid_high = target_mem_read32(t, NRF51_FICR_DEVICEID_HIGH);
gdb_outf("Device ID: 0x%08X%08X\n", deviceid_high, deviceid_low);
tc_printf(t, "Device ID: 0x%08X%08X\n", deviceid_high, deviceid_low);
return true;
}
@ -301,20 +299,20 @@ static bool nrf51_cmd_read_deviceaddr(target *t)
uint32_t addr_high = target_mem_read32(t, NRF51_FICR_DEVICEADDR_HIGH) & 0xFFFF;
if ((addr_type & 1) == 0) {
gdb_outf("Publicly Listed Address: 0x%04X%08X\n", addr_high, addr_low);
tc_printf(t, "Publicly Listed Address: 0x%04X%08X\n", addr_high, addr_low);
} else {
gdb_outf("Randomly Assigned Address: 0x%04X%08X\n", addr_high, addr_low);
tc_printf(t, "Randomly Assigned Address: 0x%04X%08X\n", addr_high, addr_low);
}
return true;
}
static bool nrf51_cmd_read_help(void)
static bool nrf51_cmd_read_help(target *t)
{
const struct command_s *c;
gdb_out("Read commands:\n");
tc_printf(t, "Read commands:\n");
for(c = nrf51_read_cmd_list; c->cmd; c++)
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
tc_printf(t, "\t%s -- %s\n", c->cmd, c->help);
return true;
}
@ -330,6 +328,6 @@ static bool nrf51_cmd_read(target *t, int argc, const char *argv[])
return !c->handler(t, argc - 1, &argv[1]);
}
return nrf51_cmd_read_help();
return nrf51_cmd_read_help(t);
}

View File

@ -25,14 +25,12 @@
*/
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "target_internal.h"
static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int sam3x_flash_write(struct target_flash *f, uint32_t dest,
static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int sam3_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int sam3x_flash_write(struct target_flash *f, target_addr dest,
const void *src, size_t len);
static bool sam3x_cmd_gpnvm_get(target *t);
@ -283,7 +281,7 @@ static uint32_t sam3x_flash_base(target *t)
return SAM3N_EEFC_BASE;
}
static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
uint32_t base = ((struct sam_flash *)f)->eefc_base;
@ -306,7 +304,7 @@ static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
return 0;
}
static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int sam3_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
/* The SAM3X/SAM3N don't really have a page erase function.
* We do nothing here and use Erase/Write page in flash_write.
@ -315,7 +313,7 @@ static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
return 0;
}
static int sam3x_flash_write(struct target_flash *f, uint32_t dest,
static int sam3x_flash_write(struct target_flash *f, target_addr dest,
const void *src, size_t len)
{
target *t = f->t;
@ -335,7 +333,7 @@ static bool sam3x_cmd_gpnvm_get(target *t)
uint32_t base = sam3x_flash_base(t);
sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_GGPB, 0);
gdb_outf("GPNVM: 0x%08X\n", target_mem_read32(t, EEFC_FRR(base)));
tc_printf(t, "GPNVM: 0x%08X\n", target_mem_read32(t, EEFC_FRR(base)));
return true;
}
@ -346,7 +344,7 @@ static bool sam3x_cmd_gpnvm_set(target *t, int argc, char *argv[])
uint32_t base = sam3x_flash_base(t);
if (argc != 3) {
gdb_out("usage: monitor gpnvm_set <bit> <val>\n");
tc_printf(t, "usage: monitor gpnvm_set <bit> <val>\n");
return false;
}
bit = atol(argv[1]);

View File

@ -33,16 +33,13 @@
*/
#include "general.h"
#include "jtagtap.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include "cortexm.h"
static int samd_flash_erase(struct target_flash *t, uint32_t addr, size_t len);
static int samd_flash_erase(struct target_flash *t, target_addr addr, size_t len);
static int samd_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static bool samd_cmd_erase_all(target *t);
static bool samd_cmd_lock_flash(target *t);
@ -460,7 +457,7 @@ static void samd_unlock_current_address(target *t)
/**
* Erase flash row by row
*/
static int samd_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int samd_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
while (len) {
@ -493,7 +490,7 @@ static int samd_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
* Write flash page by page
*/
static int samd_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
target *t = f->t;
@ -540,17 +537,17 @@ static bool samd_cmd_erase_all(target *t)
/* Test the protection error bit in Status A */
if (status & SAMD_STATUSA_PERR) {
gdb_outf("Erase failed due to a protection error.\n");
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) {
gdb_outf("Erase failed.\n");
tc_printf(t, "Erase failed.\n");
return true;
}
gdb_outf("Erase successful!\n");
tc_printf(t, "Erase successful!\n");
return true;
}
@ -606,7 +603,7 @@ static bool samd_cmd_unlock_flash(target *t)
static bool samd_cmd_read_userrow(target *t)
{
gdb_outf("User Row: 0x%08x%08x\n",
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));
@ -618,13 +615,13 @@ static bool samd_cmd_read_userrow(target *t)
*/
static bool samd_cmd_serial(target *t)
{
gdb_outf("Serial Number: 0x");
tc_printf(t, "Serial Number: 0x");
for (uint32_t i = 0; i < 4; i++) {
gdb_outf("%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i)));
tc_printf(t, "%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i)));
}
gdb_outf("\n");
tc_printf(t, "\n");
return true;
}
@ -668,16 +665,16 @@ static bool samd_cmd_mbist(target *t)
/* Test the protection error bit in Status A */
if (status & SAMD_STATUSA_PERR) {
gdb_outf("MBIST not run due to protection error.\n");
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) {
gdb_outf("MBIST Fail @ 0x%08x\n",
target_mem_read32(t, SAMD_DSU_ADDRESS));
tc_printf(t, "MBIST Fail @ 0x%08x\n",
target_mem_read32(t, SAMD_DSU_ADDRESS));
} else {
gdb_outf("MBIST Passed!\n");
tc_printf(t, "MBIST Passed!\n");
}
return true;
@ -696,8 +693,8 @@ static bool samd_cmd_ssb(target *t)
if (target_check_error(t))
return -1;
gdb_outf("Set the security bit! "
"You will need to issue 'monitor erase_mass' to clear this.\n");
tc_printf(t, "Set the security bit! "
"You will need to issue 'monitor erase_mass' to clear this.\n");
return true;
}

View File

@ -30,11 +30,9 @@
*/
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "command.h"
#include "gdb_packet.h"
static bool stm32f1_cmd_erase_mass(target *t);
static bool stm32f1_cmd_option(target *t, int argc, char *argv[]);
@ -47,9 +45,9 @@ const struct command_s stm32f1_cmd_list[] = {
static int stm32f1_flash_erase(struct target_flash *f,
uint32_t addr, size_t len);
target_addr addr, size_t len);
static int stm32f1_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
/* Flash Program ad Erase Controller Register Map */
#define FPEC_BASE 0x40022000
@ -91,7 +89,7 @@ static int stm32f1_flash_write(struct target_flash *f,
#define FLASHSIZE_F0 0x1FFFF7CC
static const uint16_t stm32f1_flash_write_stub[] = {
#include "../flashstub/stm32f1.stub"
#include "flashstub/stm32f1.stub"
};
#define SRAM_BASE 0x20000000
@ -167,7 +165,7 @@ bool stm32f1_probe(target *t)
}
flash_size = (target_mem_read32(t, FLASHSIZE_F0) & 0xffff) *0x400;
gdb_outf("flash size %d block_size %d\n", flash_size, block_size);
tc_printf(t, "flash size %d block_size %d\n", flash_size, block_size);
target_add_ram(t, 0x20000000, 0x5000);
stm32f1_add_flash(t, 0x8000000, flash_size, block_size);
target_add_commands(t, stm32f1_cmd_list, "STM32F0");
@ -181,7 +179,7 @@ static void stm32f1_flash_unlock(target *t)
}
static int stm32f1_flash_erase(struct target_flash *f,
uint32_t addr, size_t len)
target_addr addr, size_t len)
{
target *t = f->t;
uint16_t sr;
@ -214,7 +212,7 @@ static int stm32f1_flash_erase(struct target_flash *f,
}
static int stm32f1_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
target *t = f->t;
/* Write stub and data to target ram and set PC */
@ -324,16 +322,16 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
stm32f1_option_erase(t);
stm32f1_option_write_erased(t, FLASH_OBP_RDP, flash_obp_rdp_key);
} else if (rdprt) {
gdb_out("Device is Read Protected\n");
gdb_out("Use \"monitor option erase\" to unprotect, erasing device\n");
tc_printf(t, "Device is Read Protected\n");
tc_printf(t, "Use \"monitor option erase\" to unprotect, erasing device\n");
return true;
} else if (argc == 3) {
addr = strtol(argv[1], NULL, 0);
val = strtol(argv[2], NULL, 0);
stm32f1_option_write(t, addr, val);
} else {
gdb_out("usage: monitor option erase\n");
gdb_out("usage: monitor option <addr> <value>\n");
tc_printf(t, "usage: monitor option erase\n");
tc_printf(t, "usage: monitor option <addr> <value>\n");
}
if (0 && flash_obp_rdp_key == FLASH_OBP_RDP_KEY_F3) {
@ -348,8 +346,8 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[])
for (int i = 0; i < 0xf; i += 4) {
addr = 0x1ffff800 + i;
val = target_mem_read32(t, addr);
gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF);
gdb_outf("0x%08X: 0x%04X\n", addr + 2, val >> 16);
tc_printf(t, "0x%08X: 0x%04X\n", addr, val & 0xFFFF);
tc_printf(t, "0x%08X: 0x%04X\n", addr + 2, val >> 16);
}
return true;
}

View File

@ -31,11 +31,9 @@
*/
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "command.h"
#include "gdb_packet.h"
static bool stm32f4_cmd_erase_mass(target *t);
static bool stm32f4_cmd_option(target *t, int argc, char *argv[]);
@ -47,9 +45,9 @@ const struct command_s stm32f4_cmd_list[] = {
};
static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int stm32f4_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int stm32f4_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static const char stm32f4_driver_str[] = "STM32F4xx";
static const char stm32f7_driver_str[] = "STM32F7xx";
@ -106,7 +104,7 @@ static const char stm32f2_driver_str[] = "STM32F2xx";
/* This routine uses word access. Only usable on target voltage >2.7V */
static const uint16_t stm32f4_flash_write_stub[] = {
#include "../flashstub/stm32f4.stub"
#include "flashstub/stm32f4.stub"
};
#define SRAM_BASE 0x20000000
@ -221,7 +219,7 @@ static void stm32f4_flash_unlock(target *t)
}
}
static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int stm32f4_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
uint16_t sr;
@ -256,7 +254,7 @@ static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len
}
static int stm32f4_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
/* Write buffer to target ram call stub */
target_mem_write(f->t, SRAM_BASE, stm32f4_flash_write_stub,
@ -271,7 +269,7 @@ static bool stm32f4_cmd_erase_mass(target *t)
const char spinner[] = "|/-\\";
int spinindex = 0;
gdb_out("Erasing flash... This may take a few seconds. ");
tc_printf(t, "Erasing flash... This may take a few seconds. ");
stm32f4_flash_unlock(t);
/* Flash mass erase start instruction */
@ -280,13 +278,13 @@ static bool stm32f4_cmd_erase_mass(target *t)
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
gdb_outf("\b%c", spinner[spinindex++ % 4]);
tc_printf(t, "\b%c", spinner[spinindex++ % 4]);
if(target_check_error(t)) {
gdb_out("\n");
tc_printf(t, "\n");
return false;
}
}
gdb_out("\n");
tc_printf(t, "\n");
/* Check for error */
uint16_t sr = target_mem_read32(t, FLASH_SR);
@ -337,14 +335,14 @@ static bool stm32f4_cmd_option(target *t, int argc, char *argv[])
val = strtoul(argv[2], NULL, 0);
stm32f4_option_write(t, val);
} else {
gdb_out("usage: monitor option erase\n");
gdb_out("usage: monitor option write <value>\n");
tc_printf(t, "usage: monitor option erase\n");
tc_printf(t, "usage: monitor option write <value>\n");
}
for (int i = 0; i < len; i += 8) {
uint32_t addr = start + i;
val = target_mem_read32(t, addr);
gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF);
tc_printf(t, "0x%08X: 0x%04X\n", addr, val & 0xFFFF);
}
return true;
}

View File

@ -74,25 +74,84 @@
*/
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "command.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include "cortexm.h"
#include "stm32lx-nvm.h"
#define STM32Lx_NVM_PECR(p) ((p) + 0x04)
#define STM32Lx_NVM_PEKEYR(p) ((p) + 0x0C)
#define STM32Lx_NVM_PRGKEYR(p) ((p) + 0x10)
#define STM32Lx_NVM_OPTKEYR(p) ((p) + 0x14)
#define STM32Lx_NVM_SR(p) ((p) + 0x18)
#define STM32Lx_NVM_OPTR(p) ((p) + 0x1C)
#define STM32L0_NVM_PHYS (0x40022000ul)
#define STM32L0_NVM_OPT_SIZE (12)
#define STM32L0_NVM_EEPROM_SIZE (2*1024)
#define STM32L1_NVM_PHYS (0x40023c00ul)
#define STM32L1_NVM_OPT_SIZE (32)
#define STM32L1_NVM_EEPROM_SIZE (16*1024)
#define STM32Lx_NVM_OPT_PHYS 0x1ff80000ul
#define STM32Lx_NVM_EEPROM_PHYS 0x08080000ul
#define STM32Lx_NVM_PEKEY1 (0x89abcdeful)
#define STM32Lx_NVM_PEKEY2 (0x02030405ul)
#define STM32Lx_NVM_PRGKEY1 (0x8c9daebful)
#define STM32Lx_NVM_PRGKEY2 (0x13141516ul)
#define STM32Lx_NVM_OPTKEY1 (0xfbead9c8ul)
#define STM32Lx_NVM_OPTKEY2 (0x24252627ul)
#define STM32Lx_NVM_PECR_OBL_LAUNCH (1<<18)
#define STM32Lx_NVM_PECR_ERRIE (1<<17)
#define STM32Lx_NVM_PECR_EOPIE (1<<16)
#define STM32Lx_NVM_PECR_FPRG (1<<10)
#define STM32Lx_NVM_PECR_ERASE (1<< 9)
#define STM32Lx_NVM_PECR_FIX (1<< 8) /* FTDW */
#define STM32Lx_NVM_PECR_DATA (1<< 4)
#define STM32Lx_NVM_PECR_PROG (1<< 3)
#define STM32Lx_NVM_PECR_OPTLOCK (1<< 2)
#define STM32Lx_NVM_PECR_PRGLOCK (1<< 1)
#define STM32Lx_NVM_PECR_PELOCK (1<< 0)
#define STM32Lx_NVM_SR_NOTZEROERR (1<<16)
#define STM32Lx_NVM_SR_SIZERR (1<<10)
#define STM32Lx_NVM_SR_PGAERR (1<<9)
#define STM32Lx_NVM_SR_WRPERR (1<<8)
#define STM32Lx_NVM_SR_EOP (1<<1)
#define STM32Lx_NVM_SR_BSY (1<<0)
#define STM32Lx_NVM_SR_ERR_M (STM32Lx_NVM_SR_WRPERR | \
STM32Lx_NVM_SR_PGAERR | \
STM32Lx_NVM_SR_SIZERR | \
STM32Lx_NVM_SR_NOTZEROERR)
#define STM32L0_NVM_OPTR_BOOT1 (1<<31)
#define STM32Lx_NVM_OPTR_WDG_SW (1<<20)
#define STM32L0_NVM_OPTR_WPRMOD (1<<8)
#define STM32Lx_NVM_OPTR_RDPROT_S (0)
#define STM32Lx_NVM_OPTR_RDPROT_M (0xff)
#define STM32Lx_NVM_OPTR_RDPROT_0 (0xaa)
#define STM32Lx_NVM_OPTR_RDPROT_2 (0xcc)
#define STM32L1_NVM_OPTR_nBFB2 (1<<23)
#define STM32L1_NVM_OPTR_nRST_STDBY (1<<22)
#define STM32L1_NVM_OPTR_nRST_STOP (1<<21)
#define STM32L1_NVM_OPTR_BOR_LEV_S (16)
#define STM32L1_NVM_OPTR_BOR_LEV_M (0xf)
#define STM32L1_NVM_OPTR_SPRMOD (1<<8)
static int stm32lx_nvm_prog_erase(struct target_flash* f,
uint32_t addr, size_t len);
target_addr addr, size_t len);
static int stm32lx_nvm_prog_write(struct target_flash* f,
uint32_t destination,
target_addr destination,
const void* src,
size_t size);
static int stm32lx_nvm_data_erase(struct target_flash* f,
uint32_t addr, size_t len);
target_addr addr, size_t len);
static int stm32lx_nvm_data_write(struct target_flash* f,
uint32_t destination,
target_addr destination,
const void* source,
size_t size);
@ -263,7 +322,7 @@ static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm)
flash array is erased for all pages from addr to addr+len
inclusive. NVM register file address chosen from target. */
static int stm32lx_nvm_prog_erase(struct target_flash* f,
uint32_t addr, size_t len)
target_addr addr, size_t len)
{
target *t = f->t;
const size_t page_size = f->blocksize;
@ -313,7 +372,7 @@ static int stm32lx_nvm_prog_erase(struct target_flash* f,
/** Write to program flash using operations through the debug
interface. */
static int stm32lx_nvm_prog_write(struct target_flash *f,
uint32_t dest,
target_addr dest,
const void* src,
size_t size)
{
@ -356,7 +415,7 @@ static int stm32lx_nvm_prog_write(struct target_flash *f,
addr+len, inclusive, on a word boundary. NVM register file
address chosen from target. */
static int stm32lx_nvm_data_erase(struct target_flash *f,
uint32_t addr, size_t len)
target_addr addr, size_t len)
{
target *t = f->t;
const size_t page_size = f->blocksize;
@ -408,7 +467,7 @@ static int stm32lx_nvm_data_erase(struct target_flash *f,
destination writes are supported (though unaligned sources are
not). */
static int stm32lx_nvm_data_write(struct target_flash *f,
uint32_t destination,
target_addr destination,
const void* src,
size_t size)
{
@ -516,7 +575,7 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
const size_t opt_size = stm32lx_nvm_option_size(t);
if (!stm32lx_nvm_opt_unlock(t, nvm)) {
gdb_out("unable to unlock NVM option bytes\n");
tc_printf(t, "unable to unlock NVM option bytes\n");
return true;
}
@ -529,25 +588,25 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
else if (argc == 4 && !strncasecmp(argv[1], "raw", cb)) {
uint32_t addr = strtoul(argv[2], NULL, 0);
uint32_t val = strtoul(argv[3], NULL, 0);
gdb_outf("raw %08x <- %08x\n", addr, val);
tc_printf(t, "raw %08x <- %08x\n", addr, val);
if ( addr < STM32Lx_NVM_OPT_PHYS
|| addr >= STM32Lx_NVM_OPT_PHYS + opt_size
|| (addr & 3))
goto usage;
if (!stm32lx_option_write(t, addr, val))
gdb_out("option write failed\n");
tc_printf(t, "option write failed\n");
}
else if (argc == 4 && !strncasecmp(argv[1], "write", cb)) {
uint32_t addr = strtoul(argv[2], NULL, 0);
uint32_t val = strtoul(argv[3], NULL, 0);
val = (val & 0xffff) | ((~val & 0xffff) << 16);
gdb_outf("write %08x <- %08x\n", addr, val);
tc_printf(t, "write %08x <- %08x\n", addr, val);
if ( addr < STM32Lx_NVM_OPT_PHYS
|| addr >= STM32Lx_NVM_OPT_PHYS + opt_size
|| (addr & 3))
goto usage;
if (!stm32lx_option_write(t, addr, val))
gdb_out("option write failed\n");
tc_printf(t, "option write failed\n");
}
else if (argc == 2 && !strncasecmp(argv[1], "show", cb))
;
@ -558,66 +617,66 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv)
for(unsigned i = 0; i < opt_size; i += sizeof(uint32_t)) {
uint32_t addr = STM32Lx_NVM_OPT_PHYS + i;
uint32_t val = target_mem_read32(t, addr);
gdb_outf("0x%08x: 0x%04x 0x%04x %s\n",
addr, val & 0xffff, (val >> 16) & 0xffff,
((val & 0xffff) == ((~val >> 16) & 0xffff))
? "OK" : "ERR");
tc_printf(t, "0x%08x: 0x%04x 0x%04x %s\n",
addr, val & 0xffff, (val >> 16) & 0xffff,
((val & 0xffff) == ((~val >> 16) & 0xffff))
? "OK" : "ERR");
}
if (stm32lx_is_stm32l1(t)) {
uint32_t optr = target_mem_read32(t, STM32Lx_NVM_OPTR(nvm));
uint8_t rdprot = (optr >> STM32L1_NVM_OPTR_RDPROT_S)
& STM32L1_NVM_OPTR_RDPROT_M;
if (rdprot == STM32L1_NVM_OPTR_RDPROT_0)
uint8_t rdprot = (optr >> STM32Lx_NVM_OPTR_RDPROT_S)
& STM32Lx_NVM_OPTR_RDPROT_M;
if (rdprot == STM32Lx_NVM_OPTR_RDPROT_0)
rdprot = 0;
else if (rdprot == STM32L1_NVM_OPTR_RDPROT_2)
else if (rdprot == STM32Lx_NVM_OPTR_RDPROT_2)
rdprot = 2;
else
rdprot = 1;
gdb_outf("OPTR: 0x%08x, RDPRT %d, SPRMD %d, "
"BOR %d, WDG_SW %d, nRST_STP %d, nRST_STBY %d, "
"nBFB2 %d\n",
optr, rdprot,
(optr & STM32L1_NVM_OPTR_SPRMOD) ? 1 : 0,
(optr >> STM32L1_NVM_OPTR_BOR_LEV_S)
& STM32L1_NVM_OPTR_BOR_LEV_M,
(optr & STM32L1_NVM_OPTR_WDG_SW) ? 1 : 0,
(optr & STM32L1_NVM_OPTR_nRST_STOP) ? 1 : 0,
(optr & STM32L1_NVM_OPTR_nRST_STDBY) ? 1 : 0,
(optr & STM32L1_NVM_OPTR_nBFB2) ? 1 : 0);
tc_printf(t, "OPTR: 0x%08x, RDPRT %d, SPRMD %d, "
"BOR %d, WDG_SW %d, nRST_STP %d, nRST_STBY %d, "
"nBFB2 %d\n",
optr, rdprot,
(optr & STM32L1_NVM_OPTR_SPRMOD) ? 1 : 0,
(optr >> STM32L1_NVM_OPTR_BOR_LEV_S)
& STM32L1_NVM_OPTR_BOR_LEV_M,
(optr & STM32Lx_NVM_OPTR_WDG_SW) ? 1 : 0,
(optr & STM32L1_NVM_OPTR_nRST_STOP) ? 1 : 0,
(optr & STM32L1_NVM_OPTR_nRST_STDBY) ? 1 : 0,
(optr & STM32L1_NVM_OPTR_nBFB2) ? 1 : 0);
}
else {
uint32_t optr = target_mem_read32(t, STM32Lx_NVM_OPTR(nvm));
uint8_t rdprot = (optr >> STM32L0_NVM_OPTR_RDPROT_S)
& STM32L0_NVM_OPTR_RDPROT_M;
if (rdprot == STM32L0_NVM_OPTR_RDPROT_0)
uint8_t rdprot = (optr >> STM32Lx_NVM_OPTR_RDPROT_S)
& STM32Lx_NVM_OPTR_RDPROT_M;
if (rdprot == STM32Lx_NVM_OPTR_RDPROT_0)
rdprot = 0;
else if (rdprot == STM32L0_NVM_OPTR_RDPROT_2)
else if (rdprot == STM32Lx_NVM_OPTR_RDPROT_2)
rdprot = 2;
else
rdprot = 1;
gdb_outf("OPTR: 0x%08x, RDPROT %d, WPRMOD %d, WDG_SW %d, "
"BOOT1 %d\n",
optr, rdprot,
(optr & STM32L0_NVM_OPTR_WPRMOD) ? 1 : 0,
(optr & STM32L0_NVM_OPTR_WDG_SW) ? 1 : 0,
(optr & STM32L0_NVM_OPTR_BOOT1) ? 1 : 0);
tc_printf(t, "OPTR: 0x%08x, RDPROT %d, WPRMOD %d, WDG_SW %d, "
"BOOT1 %d\n",
optr, rdprot,
(optr & STM32L0_NVM_OPTR_WPRMOD) ? 1 : 0,
(optr & STM32Lx_NVM_OPTR_WDG_SW) ? 1 : 0,
(optr & STM32L0_NVM_OPTR_BOOT1) ? 1 : 0);
}
goto done;
usage:
gdb_out("usage: monitor option [ARGS]\n");
gdb_out(" show - Show options in NVM and as"
" loaded\n");
gdb_out(" obl_launch - Reload options from NVM\n");
gdb_out(" write <addr> <value16> - Set option half-word; "
"complement computed\n");
gdb_out(" raw <addr> <value32> - Set option word\n");
gdb_outf("The value of <addr> must be word aligned and from 0x%08x "
"to +0x%x\n",
STM32Lx_NVM_OPT_PHYS,
STM32Lx_NVM_OPT_PHYS + opt_size - sizeof(uint32_t));
tc_printf(t, "usage: monitor option [ARGS]\n");
tc_printf(t, " show - Show options in NVM and as"
" loaded\n");
tc_printf(t, " obl_launch - Reload options from NVM\n");
tc_printf(t, " write <addr> <value16> - Set option half-word; "
"complement computed\n");
tc_printf(t, " raw <addr> <value32> - Set option word\n");
tc_printf(t, "The value of <addr> must be word aligned and from 0x%08x "
"to +0x%x\n",
STM32Lx_NVM_OPT_PHYS,
STM32Lx_NVM_OPT_PHYS + opt_size - sizeof(uint32_t));
done:
stm32lx_nvm_lock(t, nvm);
@ -630,7 +689,7 @@ static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv)
const uint32_t nvm = stm32lx_nvm_phys(t);
if (!stm32lx_nvm_prog_data_unlock(t, nvm)) {
gdb_out("unable to unlock EEPROM\n");
tc_printf(t, "unable to unlock EEPROM\n");
return true;
}
@ -646,23 +705,23 @@ static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv)
goto usage;
if (!strncasecmp(argv[1], "byte", cb)) {
gdb_outf("write byte 0x%08x <- 0x%08x\n", addr, val);
tc_printf(t, "write byte 0x%08x <- 0x%08x\n", addr, val);
if (!stm32lx_eeprom_write(t, addr, 1, val))
gdb_out("eeprom write failed\n");
tc_printf(t, "eeprom write failed\n");
} else if (!strncasecmp(argv[1], "halfword", cb)) {
val &= 0xffff;
gdb_outf("write halfword 0x%08x <- 0x%04x\n",
tc_printf(t, "write halfword 0x%08x <- 0x%04x\n",
addr, val);
if (addr & 1)
goto usage;
if (!stm32lx_eeprom_write(t, addr, 2, val))
gdb_out("eeprom write failed\n");
tc_printf(t, "eeprom write failed\n");
} else if (!strncasecmp(argv[1], "word", cb)) {
gdb_outf("write word 0x%08x <- 0x%08x\n", addr, val);
tc_printf(t, "write word 0x%08x <- 0x%08x\n", addr, val);
if (addr & 3)
goto usage;
if (!stm32lx_eeprom_write(t, addr, 4, val))
gdb_out("eeprom write failed\n");
tc_printf(t, "eeprom write failed\n");
}
else
goto usage;
@ -673,14 +732,13 @@ static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv)
goto done;
usage:
gdb_out("usage: monitor eeprom [ARGS]\n");
gdb_out(" byte <addr> <value8> - Write a byte\n");
gdb_out(" halfword <addr> <value16> - Write a half-word\n");
gdb_out(" word <addr> <value32> - Write a word\n");
gdb_outf("The value of <addr> must in the interval [0x%08x, 0x%x)\n",
STM32Lx_NVM_EEPROM_PHYS,
STM32Lx_NVM_EEPROM_PHYS
+ stm32lx_nvm_eeprom_size(t));
tc_printf(t, "usage: monitor eeprom [ARGS]\n");
tc_printf(t, " byte <addr> <value8> - Write a byte\n");
tc_printf(t, " halfword <addr> <value16> - Write a half-word\n");
tc_printf(t, " word <addr> <value32> - Write a word\n");
tc_printf(t, "The value of <addr> must in the interval [0x%08x, 0x%x)\n",
STM32Lx_NVM_EEPROM_PHYS,
STM32Lx_NVM_EEPROM_PHYS + stm32lx_nvm_eeprom_size(t));
done:
stm32lx_nvm_lock(t, nvm);

View File

@ -31,11 +31,9 @@
*/
#include "general.h"
#include "adiv5.h"
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "command.h"
#include "gdb_packet.h"
static bool stm32l4_cmd_erase_mass(target *t);
static bool stm32l4_cmd_erase_bank1(target *t);
@ -51,9 +49,9 @@ const struct command_s stm32l4_cmd_list[] = {
};
static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int stm32l4_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len);
target_addr dest, const void *src, size_t len);
static const char stm32l4_driver_str[] = "STM32L4xx";
@ -112,7 +110,7 @@ static const char stm32l4_driver_str[] = "STM32L4xx";
/* This routine is uses double word access.*/
static const uint16_t stm32l4_flash_write_stub[] = {
#include "../flashstub/stm32l4.stub"
#include "flashstub/stm32l4.stub"
};
#define SRAM_BASE 0x20000000
@ -173,7 +171,7 @@ static void stm32l4_flash_unlock(target *t)
}
}
static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
uint16_t sr;
@ -214,7 +212,7 @@ static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len
}
static int stm32l4_flash_write(struct target_flash *f,
uint32_t dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
/* Write buffer to target ram call stub */
target_mem_write(f->t, SRAM_BASE, stm32l4_flash_write_stub,
@ -229,7 +227,7 @@ static bool stm32l4_cmd_erase(target *t, uint32_t action)
const char spinner[] = "|/-\\";
int spinindex = 0;
gdb_out("Erasing flash... This may take a few seconds. ");
tc_printf(t, "Erasing flash... This may take a few seconds. ");
stm32l4_flash_unlock(t);
/* Flash erase action start instruction */
@ -238,13 +236,13 @@ static bool stm32l4_cmd_erase(target *t, uint32_t action)
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
gdb_outf("\b%c", spinner[spinindex++ % 4]);
tc_printf(t, "\b%c", spinner[spinindex++ % 4]);
if(target_check_error(t)) {
gdb_out("\n");
tc_printf(t, "\n");
return false;
}
}
gdb_out("\n");
tc_printf(t, "\n");
/* Check for error */
uint16_t sr = target_mem_read32(t, FLASH_SR);
@ -277,12 +275,12 @@ static bool stm32l4_cmd_option(target *t, int argc, char *argv[])
for (int i = 0; i < 0x23; i += 8) {
addr = 0x1fff7800 + i;
val = target_mem_read32(t, addr);
gdb_outf("0x%08X: 0x%08x\n", addr, val);
tc_printf(t, "0x%08X: 0x%08x\n", addr, val);
}
for (int i = 8; i < 0x23; i += 8) {
addr = 0x1ffff800 + i;
val = target_mem_read32(t, addr);
gdb_outf("0x%08X: 0x%08X\n", addr, val);
tc_printf(t, "0x%08X: 0x%08X\n", addr, val);
}
return true;
}

View File

@ -0,0 +1,79 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
#include "general.h"
#include "swdptap.h"
uint32_t __attribute__((weak))
swdptap_seq_in(int ticks)
{
uint32_t index = 1;
uint32_t ret = 0;
while (ticks--) {
if (swdptap_bit_in())
ret |= index;
index <<= 1;
}
return ret;
}
bool __attribute__((weak))
swdptap_seq_in_parity(uint32_t *ret, int ticks)
{
uint32_t index = 1;
uint8_t parity = 0;
*ret = 0;
while (ticks--) {
if (swdptap_bit_in()) {
*ret |= index;
parity ^= 1;
}
index <<= 1;
}
if (swdptap_bit_in())
parity ^= 1;
return parity;
}
void __attribute__((weak))
swdptap_seq_out(uint32_t MS, int ticks)
{
while (ticks--) {
swdptap_bit_out(MS & 1);
MS >>= 1;
}
}
void __attribute__((weak))
swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t parity = 0;
while (ticks--) {
swdptap_bit_out(MS & 1);
parity ^= MS;
MS >>= 1;
}
swdptap_bit_out(parity & 1);
}

554
src/target/target.c Normal file
View File

@ -0,0 +1,554 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2016 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include <stdarg.h>
target *target_list = NULL;
target *target_new(void)
{
target *t = (void*)calloc(1, sizeof(*t));
t->next = target_list;
target_list = t;
return t;
}
bool target_foreach(void (*cb)(int, target *t, void *context), void *context)
{
int i = 1;
target *t = target_list;
for (; t; t = t->next, i++)
cb(i, t, context);
return target_list != NULL;
}
void target_list_free(void)
{
struct target_command_s *tc;
while(target_list) {
target *t = target_list->next;
if (target_list->tc)
target_list->tc->destroy_callback(target_list->tc, target_list);
if (target_list->priv)
target_list->priv_free(target_list->priv);
while (target_list->commands) {
tc = target_list->commands->next;
free(target_list->commands);
target_list->commands = tc;
}
if (target_list->dyn_mem_map)
free(target_list->dyn_mem_map);
while (target_list->ram) {
void * next = target_list->ram->next;
free(target_list->ram);
target_list->ram = next;
}
while (target_list->flash) {
void * next = target_list->flash->next;
if (target_list->flash->buf)
free(target_list->flash->buf);
free(target_list->flash);
target_list->flash = next;
}
while (target_list->bw_list) {
void * next = target_list->bw_list->next;
free(target_list->bw_list);
target_list->bw_list = next;
}
free(target_list);
target_list = t;
}
}
void target_add_commands(target *t, const struct command_s *cmds, const char *name)
{
struct target_command_s *tc;
if (t->commands) {
for (tc = t->commands; tc->next; tc = tc->next);
tc = tc->next = malloc(sizeof(*tc));
} else {
t->commands = tc = malloc(sizeof(*tc));
}
tc->specific_name = name;
tc->cmds = cmds;
tc->next = NULL;
}
target *target_attach_n(int n, struct target_controller *tc)
{
target *t;
int i;
for(t = target_list, i = 1; t; t = t->next, i++)
if(i == n)
return target_attach(t, tc);
return NULL;
}
target *target_attach(target *t, struct target_controller *tc)
{
if (t->tc)
t->tc->destroy_callback(t->tc, t);
t->tc = tc;
if (!t->attach(t))
return NULL;
t->attached = true;
return t;
}
void target_add_ram(target *t, target_addr start, uint32_t len)
{
struct target_ram *ram = malloc(sizeof(*ram));
ram->start = start;
ram->length = len;
ram->next = t->ram;
t->ram = ram;
}
void target_add_flash(target *t, struct target_flash *f)
{
f->t = t;
f->next = t->flash;
t->flash = f;
}
static ssize_t map_ram(char *buf, size_t len, struct target_ram *ram)
{
return snprintf(buf, len, "<memory type=\"ram\" start=\"0x%08"PRIx32
"\" length=\"0x%08zx\"/>",
ram->start, ram->length);
}
static ssize_t map_flash(char *buf, size_t len, struct target_flash *f)
{
int i = 0;
i += snprintf(&buf[i], len - i, "<memory type=\"flash\" start=\"0x%08"PRIx32
"\" length=\"0x%08zx\">",
f->start, f->length);
i += snprintf(&buf[i], len - i, "<property name=\"blocksize\">0x%08zx"
"</property></memory>",
f->blocksize);
return i;
}
const char *target_mem_map(target *t)
{
if (t->dyn_mem_map)
return t->dyn_mem_map;
/* FIXME size buffer */
size_t len = 1024;
char *tmp = malloc(len);
size_t i = 0;
i = snprintf(&tmp[i], len - i, "<memory-map>");
/* Map each defined RAM */
for (struct target_ram *r = t->ram; r; r = r->next)
i += map_ram(&tmp[i], len - i, r);
/* Map each defined Flash */
for (struct target_flash *f = t->flash; f; f = f->next)
i += map_flash(&tmp[i], len - i, f);
i += snprintf(&tmp[i], len - i, "</memory-map>");
t->dyn_mem_map = tmp;
return t->dyn_mem_map;
}
static struct target_flash *flash_for_addr(target *t, uint32_t addr)
{
for (struct target_flash *f = t->flash; f; f = f->next)
if ((f->start <= addr) &&
(addr < (f->start + f->length)))
return f;
return NULL;
}
int target_flash_erase(target *t, target_addr addr, size_t len)
{
int ret = 0;
while (len) {
struct target_flash *f = flash_for_addr(t, addr);
size_t tmplen = MIN(len, f->length - (addr % f->length));
ret |= f->erase(f, addr, tmplen);
addr += tmplen;
len -= tmplen;
}
return ret;
}
int target_flash_write(target *t,
target_addr dest, const void *src, size_t len)
{
int ret = 0;
while (len) {
struct target_flash *f = flash_for_addr(t, dest);
size_t tmplen = MIN(len, f->length - (dest % f->length));
if (f->align > 1) {
uint32_t offset = dest % f->align;
uint8_t data[ALIGN(offset + len, f->align)];
memset(data, f->erased, sizeof(data));
memcpy((uint8_t *)data + offset, src, len);
ret |= f->write(f, dest - offset, data, sizeof(data));
} else {
ret |= f->write(f, dest, src, tmplen);
}
src += tmplen;
len -= tmplen;
}
return ret;
}
int target_flash_done(target *t)
{
for (struct target_flash *f = t->flash; f; f = f->next) {
if (f->done) {
int tmp = f->done(f);
if (tmp)
return tmp;
}
}
return 0;
}
int target_flash_write_buffered(struct target_flash *f,
target_addr dest, const void *src, size_t len)
{
int ret = 0;
if (f->buf == NULL) {
/* Allocate flash sector buffer */
f->buf = malloc(f->buf_size);
f->buf_addr = -1;
}
while (len) {
uint32_t offset = dest % f->buf_size;
uint32_t base = dest - offset;
if (base != f->buf_addr) {
if (f->buf_addr != (uint32_t)-1) {
/* Write sector to flash if valid */
ret |= f->write_buf(f, f->buf_addr,
f->buf, f->buf_size);
}
/* Setup buffer for a new sector */
f->buf_addr = base;
memset(f->buf, f->erased, f->buf_size);
}
/* Copy chunk into sector buffer */
size_t sectlen = MIN(f->buf_size - offset, len);
memcpy(f->buf + offset, src, sectlen);
dest += sectlen;
src += sectlen;
len -= sectlen;
}
return ret;
}
int target_flash_done_buffered(struct target_flash *f)
{
int ret = 0;
if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) {
/* Write sector to flash if valid */
ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size);
f->buf_addr = -1;
free(f->buf);
f->buf = NULL;
}
return ret;
}
/* Wrapper functions */
void target_detach(target *t)
{
t->detach(t);
t->attached = false;
}
bool target_check_error(target *t) { return t->check_error(t); }
bool target_attached(target *t) { return t->attached; }
/* Memory access functions */
int target_mem_read(target *t, void *dest, target_addr src, size_t len)
{
t->mem_read(t, dest, src, len);
return target_check_error(t);
}
int target_mem_write(target *t, target_addr dest, const void *src, size_t len)
{
t->mem_write(t, dest, src, len);
return target_check_error(t);
}
/* Register access functions */
void target_regs_read(target *t, void *data) { t->regs_read(t, data); }
void target_regs_write(target *t, const void *data) { t->regs_write(t, data); }
/* Halt/resume functions */
void target_reset(target *t) { t->reset(t); }
void target_halt_request(target *t) { t->halt_request(t); }
enum target_halt_reason target_halt_poll(target *t, target_addr *watch)
{
return t->halt_poll(t, watch);
}
void target_halt_resume(target *t, bool step) { t->halt_resume(t, step); }
/* Break-/watchpoint functions */
int target_breakwatch_set(target *t,
enum target_breakwatch type, target_addr addr, size_t len)
{
struct breakwatch bw = {
.type = type,
.addr = addr,
.size = len,
};
int ret = 1;
if (t->breakwatch_set)
ret = t->breakwatch_set(t, &bw);
if (ret == 0) {
/* Success, make a heap copy and add to list */
struct breakwatch *bwm = malloc(sizeof bw);
memcpy(bwm, &bw, sizeof(bw));
bwm->next = t->bw_list;
t->bw_list = bwm;
}
return ret;
}
int target_breakwatch_clear(target *t,
enum target_breakwatch type, target_addr addr, size_t len)
{
struct breakwatch *bwp = NULL, *bw;
int ret = 1;
for (bw = t->bw_list; bw; bw = bw->next, bwp = bw)
if ((bw->type == type) &&
(bw->addr == addr) &&
(bw->size == len))
break;
if (bw == NULL)
return -1;
if (t->breakwatch_clear)
ret = t->breakwatch_clear(t, bw);
if (ret == 0) {
if (bwp == NULL) {
t->bw_list = bw->next;
} else {
bwp->next = bw->next;
}
free(bw);
}
return ret;
}
/* Accessor functions */
size_t target_regs_size(target *t)
{
return t->regs_size;
}
const char *target_tdesc(target *t)
{
return t->tdesc ? t->tdesc : "";
}
const char *target_driver_name(target *t)
{
return t->driver;
}
uint32_t target_mem_read32(target *t, uint32_t addr)
{
uint32_t ret;
t->mem_read(t, &ret, addr, sizeof(ret));
return ret;
}
void target_mem_write32(target *t, uint32_t addr, uint32_t value)
{
t->mem_write(t, addr, &value, sizeof(value));
}
uint16_t target_mem_read16(target *t, uint32_t addr)
{
uint16_t ret;
t->mem_read(t, &ret, addr, sizeof(ret));
return ret;
}
void target_mem_write16(target *t, uint32_t addr, uint16_t value)
{
t->mem_write(t, addr, &value, sizeof(value));
}
uint8_t target_mem_read8(target *t, uint32_t addr)
{
uint8_t ret;
t->mem_read(t, &ret, addr, sizeof(ret));
return ret;
}
void target_mem_write8(target *t, uint32_t addr, uint8_t value)
{
t->mem_write(t, addr, &value, sizeof(value));
}
void target_command_help(target *t)
{
for (struct target_command_s *tc = t->commands; tc; tc = tc->next) {
tc_printf(t, "%s specific commands:\n", tc->specific_name);
for(const struct command_s *c = tc->cmds; c->cmd; c++)
tc_printf(t, "\t%s -- %s\n", c->cmd, c->help);
}
}
int target_command(target *t, int argc, const char *argv[])
{
for (struct target_command_s *tc = t->commands; tc; tc = tc->next)
for(const struct command_s *c = tc->cmds; c->cmd; c++)
if(!strncmp(argv[0], c->cmd, strlen(argv[0])))
return !c->handler(t, argc, argv);
return -1;
}
void tc_printf(target *t, const char *fmt, ...)
{
(void)t;
va_list ap;
va_start(ap, fmt);
t->tc->printf(t->tc, fmt, ap);
va_end(ap);
}
/* Interface to host system calls */
int tc_open(target *t, target_addr path, size_t plen,
enum target_open_flags flags, mode_t mode)
{
if (t->tc->open == NULL) {
t->tc->errno_ = TARGET_ENFILE;
return -1;
}
return t->tc->open(t->tc, path, plen, flags, mode);
}
int tc_close(target *t, int fd)
{
if (t->tc->close == NULL) {
t->tc->errno_ = TARGET_EBADF;
return -1;
}
return t->tc->close(t->tc, fd);
}
int tc_read(target *t, int fd, target_addr buf, unsigned int count)
{
if (t->tc->read == NULL)
return 0;
return t->tc->read(t->tc, fd, buf, count);
}
int tc_write(target *t, int fd, target_addr buf, unsigned int count)
{
if (t->tc->write == NULL)
return 0;
return t->tc->write(t->tc, fd, buf, count);
}
long tc_lseek(target *t, int fd, long offset, enum target_seek_flag flag)
{
if (t->tc->lseek == NULL)
return 0;
return t->tc->lseek(t->tc, fd, offset, flag);
}
int tc_rename(target *t, target_addr oldpath, size_t oldlen,
target_addr newpath, size_t newlen)
{
if (t->tc->rename == NULL) {
t->tc->errno_ = TARGET_ENOENT;
return -1;
}
return t->tc->rename(t->tc, oldpath, oldlen, newpath, newlen);
}
int tc_unlink(target *t, target_addr path, size_t plen)
{
if (t->tc->unlink == NULL) {
t->tc->errno_ = TARGET_ENOENT;
return -1;
}
return t->tc->unlink(t->tc, path, plen);
}
int tc_stat(target *t, target_addr path, size_t plen, target_addr buf)
{
if (t->tc->stat == NULL) {
t->tc->errno_ = TARGET_ENOENT;
return -1;
}
return t->tc->stat(t->tc, path, plen, buf);
}
int tc_fstat(target *t, int fd, target_addr buf)
{
if (t->tc->fstat == NULL) {
return 0;
}
return t->tc->fstat(t->tc, fd, buf);
}
int tc_gettimeofday(target *t, target_addr tv, target_addr tz)
{
if (t->tc->gettimeofday == NULL) {
return -1;
}
return t->tc->gettimeofday(t->tc, tv, tz);
}
int tc_isatty(target *t, int fd)
{
if (t->tc->isatty == NULL) {
return 1;
}
return t->tc->isatty(t->tc, fd);
}
int tc_system(target *t, target_addr cmd, size_t cmdlen)
{
if (t->tc->system == NULL) {
return -1;
}
return t->tc->system(t->tc, cmd, cmdlen);
}

View File

@ -0,0 +1,185 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
#ifndef __TARGET_INTERNAL_H
#define __TARGET_INTERNAL_H
extern target *target_list;
target *target_new(void);
struct target_ram {
target_addr start;
size_t length;
struct target_ram *next;
};
struct target_flash;
typedef int (*flash_erase_func)(struct target_flash *f, target_addr addr, size_t len);
typedef int (*flash_write_func)(struct target_flash *f, target_addr dest,
const void *src, size_t len);
typedef int (*flash_done_func)(struct target_flash *f);
struct target_flash {
target_addr start;
size_t length;
size_t blocksize;
flash_erase_func erase;
flash_write_func write;
flash_done_func done;
target *t;
struct target_flash *next;
int align;
uint8_t erased;
/* For buffered flash */
size_t buf_size;
flash_write_func write_buf;
target_addr buf_addr;
void *buf;
};
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
struct command_s {
const char *cmd;
cmd_handler handler;
const char *help;
};
struct target_command_s {
const char *specific_name;
const struct command_s *cmds;
struct target_command_s *next;
};
struct breakwatch {
struct breakwatch *next;
enum target_breakwatch type;
target_addr addr;
size_t size;
uint32_t reserved[4]; /* for use by the implementing driver */
};
struct target_s {
bool attached;
struct target_controller *tc;
/* Attach/Detach funcitons */
bool (*attach)(target *t);
void (*detach)(target *t);
bool (*check_error)(target *t);
/* Memory access functions */
void (*mem_read)(target *t, void *dest, target_addr src,
size_t len);
void (*mem_write)(target *t, target_addr dest,
const void *src, size_t len);
/* Register access functions */
size_t regs_size;
const char *tdesc;
void (*regs_read)(target *t, void *data);
void (*regs_write)(target *t, const void *data);
/* Halt/resume functions */
void (*reset)(target *t);
void (*halt_request)(target *t);
enum target_halt_reason (*halt_poll)(target *t, target_addr *watch);
void (*halt_resume)(target *t, bool step);
/* Break-/watchpoint functions */
int (*breakwatch_set)(target *t, struct breakwatch*);
int (*breakwatch_clear)(target *t, struct breakwatch*);
struct breakwatch *bw_list;
/* target-defined options */
unsigned target_options;
uint32_t idcode;
/* Target memory map */
char *dyn_mem_map;
struct target_ram *ram;
struct target_flash *flash;
/* Other stuff */
const char *driver;
struct target_command_s *commands;
struct target_s *next;
void *priv;
void (*priv_free)(void *);
};
void target_add_commands(target *t, const struct command_s *cmds, const char *name);
void target_add_ram(target *t, target_addr start, uint32_t len);
void target_add_flash(target *t, struct target_flash *f);
int target_flash_write_buffered(struct target_flash *f,
target_addr dest, const void *src, size_t len);
int target_flash_done_buffered(struct target_flash *f);
/* Convenience function for MMIO access */
uint32_t target_mem_read32(target *t, uint32_t addr);
uint16_t target_mem_read16(target *t, uint32_t addr);
uint8_t target_mem_read8(target *t, uint32_t addr);
void target_mem_write32(target *t, uint32_t addr, uint32_t value);
void target_mem_write16(target *t, uint32_t addr, uint16_t value);
void target_mem_write8(target *t, uint32_t addr, uint8_t value);
bool target_check_error(target *t);
/* Access to host controller interface */
void tc_printf(target *t, const char *fmt, ...);
/* Interface to host system calls */
int tc_open(target *, target_addr path, size_t plen,
enum target_open_flags flags, mode_t mode);
int tc_close(target *t, int fd);
int tc_read(target *t, int fd, target_addr buf, unsigned int count);
int tc_write(target *t, int fd, target_addr buf, unsigned int count);
long tc_lseek(target *t, int fd, long offset,
enum target_seek_flag flag);
int tc_rename(target *t, target_addr oldpath, size_t oldlen,
target_addr newpath, size_t newlen);
int tc_unlink(target *t, target_addr path, size_t plen);
int tc_stat(target *t, target_addr path, size_t plen, target_addr buf);
int tc_fstat(target *t, int fd, target_addr buf);
int tc_gettimeofday(target *t, target_addr tv, target_addr tz);
int tc_isatty(target *t, int fd);
int tc_system(target *t, target_addr cmd, size_t cmdlen);
/* Probe for various targets.
* Actual functions implemented in their respective drivers.
*/
bool stm32f1_probe(target *t);
bool stm32f4_probe(target *t);
bool stm32l0_probe(target *t);
bool stm32l1_probe(target *t);
bool stm32l4_probe(target *t);
bool lmi_probe(target *t);
bool lpc11xx_probe(target *t);
bool lpc15xx_probe(target *t);
bool lpc43xx_probe(target *t);
bool sam3x_probe(target *t);
bool nrf51_probe(target *t);
bool samd_probe(target *t);
bool kinetis_probe(target *t);
bool efm32_probe(target *t);
#endif