Merge pull request #143 from gsmcmullin/work
Split target support from GDB server with clean interface.
This commit is contained in:
commit
de603f4bd8
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
38
src/crc32.c
38
src/crc32.c
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
173
src/gdb_main.c
173
src/gdb_main.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
257
src/target.c
257
src/target.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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`.
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)) {
|
|
@ -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;
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "general.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
#include "cortexm.h"
|
||||
#include "lpc_common.h"
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "general.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
#include "cortexm.h"
|
||||
#include "lpc_common.h"
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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, ¶m, 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 */
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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]);
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue