commit f1c36c3c126fe91c67dceb47dcfccf464ddbd095
parent 19e47556a4bc2d57dda7edcc557b45a03d02190d
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 10 Jan 2016 19:16:04 -0800
debugger: transport abstraction, part 1 of n
- introduce debug_transport function table
- move transport-agnostic M3/DAP debug stuff to arm-m-debug.c
- no mass renaming of functions yet
Diffstat:
6 files changed, 339 insertions(+), 37 deletions(-)
diff --git a/Makefile b/Makefile
@@ -15,6 +15,7 @@ SRCS := tools/debugger.c \
tools/debugger-core.c \
tools/debugger-commands.c \
tools/gdb-bridge.c \
+ tools/arm-m-debug.c \
tools/linenoise.c \
tools/lkdebug.c \
tools/rswdp.c \
diff --git a/tools/arm-m-debug.c b/tools/arm-m-debug.c
@@ -0,0 +1,193 @@
+/* arm-m-debug
+ *
+ * Copyright 2011 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <fw/types.h>
+#include "debugger.h"
+#include "rswdp.h"
+
+#include "arm-v7m.h"
+
+// CDBG_* comes from here right now -- FIXME
+#include <protocol/rswdp.h>
+
+static volatile int ATTN;
+
+void swdp_interrupt(void) {
+ ATTN++;
+ if (write(2, "\b\b*INTERRUPT*\n", 16)) { /* do nothing */ }
+}
+
+
+int swdp_core_write(u32 n, u32 v) {
+ if (mem_wr_32(CDBG_REG_DATA, v)) {
+ return -1;
+ }
+ if (mem_wr_32(CDBG_REG_ADDR, (n & 0x1F) | 0x10000)) {
+ return -1;
+ }
+ return 0;
+}
+
+int swdp_core_read(u32 n, u32 *v) {
+ if (mem_wr_32(CDBG_REG_ADDR, n & 0x1F)) {
+ return -1;
+ }
+ if (mem_rd_32(CDBG_REG_DATA, v)) {
+ return -1;
+ }
+ return 0;
+}
+
+int swdp_core_read_all(u32 *v) {
+ unsigned n;
+ for (n = 0; n < 19; n++) {
+ if (mem_wr_32(CDBG_REG_ADDR, n & 0x1F)) {
+ return -1;
+ }
+ if (mem_rd_32(CDBG_REG_DATA, v++)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int swdp_step_no_ints = 0;
+
+int swdp_core_halt(void) {
+ u32 x;
+ if (mem_rd_32(CDBG_CSR, &x)) return -1;
+ x &= (CDBG_C_HALT | CDBG_C_DEBUGEN | CDBG_C_MASKINTS);
+ x |= CDBG_CSR_KEY | CDBG_C_DEBUGEN | CDBG_C_HALT;
+ return mem_wr_32(CDBG_CSR, x);
+}
+
+int swdp_core_step(void) {
+ u32 x;
+ if (mem_rd_32(CDBG_CSR, &x)) return -1;
+ x &= (CDBG_C_HALT | CDBG_C_DEBUGEN | CDBG_C_MASKINTS);
+ x |= CDBG_CSR_KEY;
+
+ if (!(x & CDBG_C_HALT)) {
+ // HALT if we're not already HALTED
+ x |= CDBG_C_HALT | CDBG_C_DEBUGEN;
+ mem_wr_32(CDBG_CSR, x);
+ }
+ if (swdp_step_no_ints) {
+ // set MASKINTS if not already set
+ if (!(x & CDBG_C_MASKINTS)) {
+ x |= CDBG_C_MASKINTS;
+ mem_wr_32(CDBG_CSR, x);
+ }
+ } else {
+ // clear MASKINTs if not already clear
+ if (x & CDBG_C_MASKINTS) {
+ x &= (~CDBG_C_MASKINTS);
+ mem_wr_32(CDBG_CSR, x);
+ }
+ }
+ // STEP
+ x &= (~CDBG_C_HALT);
+ return mem_wr_32(CDBG_CSR, x | CDBG_C_STEP);
+}
+
+int swdp_core_resume(void) {
+ u32 x;
+ if (mem_rd_32(CDBG_CSR, &x)) return -1;
+ x &= (CDBG_C_HALT | CDBG_C_DEBUGEN | CDBG_C_MASKINTS);
+ x |= CDBG_CSR_KEY | CDBG_C_DEBUGEN;
+
+ if (swdp_step_no_ints > 1) {
+ // not just on during step, but always
+ if (!(x & CDBG_C_MASKINTS)) {
+ x |= CDBG_C_MASKINTS;
+ mem_wr_32(CDBG_CSR, x);
+ }
+ } else {
+ if (x & CDBG_C_MASKINTS) {
+ x &= (~CDBG_C_MASKINTS);
+ mem_wr_32(CDBG_CSR, x);
+ }
+ }
+
+ x &= ~(CDBG_C_HALT | CDBG_C_STEP);
+ return mem_wr_32(CDBG_CSR, x);
+}
+
+int swdp_core_wait_for_halt(void) {
+ int last = ATTN;
+ u32 csr;
+ for (;;) {
+ if (mem_rd_32(CDBG_CSR, &csr))
+ return -1;
+ if (csr & CDBG_S_HALT)
+ return 0;
+ if (ATTN != last)
+ return -2;
+ }
+}
+
+int swdp_ahb_wait_for_change(u32 addr, u32 oldval) {
+ int last = ATTN;
+ u32 val;
+ do {
+ if (mem_rd_32(addr, &val))
+ return -1;
+ if (ATTN != last)
+ return -2;
+ } while (val == oldval);
+ return 0;
+}
+
+int swdp_watchpoint(unsigned n, u32 addr, u32 func) {
+ int r;
+ if (n > 3)
+ return -1;
+
+ /* enable DWT, enable all exception traps */
+ r = mem_wr_32(DEMCR, DEMCR_TRCENA | DEMCR_VC_CORERESET);
+ r |= mem_wr_32(DWT_FUNC(n), DWT_FN_DISABLED);
+ if (func != DWT_FN_DISABLED) {
+ r |= mem_wr_32(DWT_COMP(n), addr);
+ r |= mem_wr_32(DWT_MASK(n), 0);
+ r |= mem_wr_32(DWT_FUNC(n), func);
+ }
+ return r;
+}
+
+int swdp_watchpoint_pc(unsigned n, u32 addr) {
+ return swdp_watchpoint(n, addr, DWT_FN_WATCH_PC);
+}
+
+int swdp_watchpoint_rd(unsigned n, u32 addr) {
+ return swdp_watchpoint(n, addr, DWT_FN_WATCH_RD);
+}
+
+int swdp_watchpoint_wr(unsigned n, u32 addr) {
+ return swdp_watchpoint(n, addr, DWT_FN_WATCH_WR);
+}
+
+int swdp_watchpoint_rw(unsigned n, u32 addr) {
+ return swdp_watchpoint(n, addr, DWT_FN_WATCH_RW);
+}
+
+int swdp_watchpoint_disable(unsigned n) {
+ return swdp_watchpoint(n, 0, DWT_FN_DISABLED);
+}
+
diff --git a/tools/debugger-core.c b/tools/debugger-core.c
@@ -595,3 +595,18 @@ int debugger_command(char *line) {
return r;
}
+static int _fail(void) {
+ return -1;
+}
+
+debug_transport DUMMY_TRANSPORT = {
+ .attach = (void*) _fail,
+ .clear_error = (void*) _fail,
+ .mem_rd_32 = (void*) _fail,
+ .mem_wr_32 = (void*) _fail,
+ .mem_rd_32_c = (void*) _fail,
+ .mem_wr_32_c = (void*) _fail,
+};
+
+debug_transport *ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
+
diff --git a/tools/debugger.h b/tools/debugger.h
@@ -82,5 +82,54 @@ extern struct debugger_command debugger_commands[];
int read_register(const char *name, u32 *value);
int read_memory_word(u32 addr, u32 *value);
+typedef struct debug_transport {
+ // attempt to establish connection to target
+ int (*attach)(void);
+
+ // returns nonzero if target is in error state
+ // (one or more transactions have failed, attach needed)
+ int (*error)(void);
+
+ // if target is in error, clear error flag
+ // return nonzero if target was in error (attach needed)
+ int (*clear_error)(void);
+
+ // single 32bit memory access
+ int (*mem_rd_32)(u32 addr, u32 *value);
+ int (*mem_wr_32)(u32 addr, u32 value);
+
+ // multiple 32bit memory access
+ int (*mem_rd_32_c)(u32 addr, u32 *data, int count);
+ int (*mem_wr_32_c)(u32 addr, u32 *data, int count);
+} debug_transport;
+
+extern debug_transport *ACTIVE_TRANSPORT;
+
+static inline int debug_attach(void) {
+ return ACTIVE_TRANSPORT->attach();
+}
+static inline int debug_error(void) {
+ return ACTIVE_TRANSPORT->error();
+}
+static inline int debug_clear_error(void) {
+ return ACTIVE_TRANSPORT->clear_error();
+}
+static inline int mem_rd_32(u32 addr, u32 *value) {
+ return ACTIVE_TRANSPORT->mem_rd_32(addr, value);
+}
+static inline int mem_wr_32(u32 addr, u32 value) {
+ return ACTIVE_TRANSPORT->mem_wr_32(addr, value);
+}
+static inline int mem_rd_32_c(u32 addr, u32 *data, int count) {
+ return ACTIVE_TRANSPORT->mem_rd_32_c(addr, data, count);
+}
+static inline int mem_wr_32_c(u32 addr, u32 *data, int count) {
+ return ACTIVE_TRANSPORT->mem_wr_32_c(addr, data, count);
+}
+
+extern debug_transport DUMMY_TRANSPORT;
+extern debug_transport SWDP_TRANSPORT;
+extern debug_transport JTAG_TRANSPORT;
+
#endif
diff --git a/tools/rswdp.c b/tools/rswdp.c
@@ -29,17 +29,10 @@
#include "rswdp.h"
#include "arm-v7m.h"
-#include <debugger.h>
+#include "debugger.h"
int swd_verbose = 0;
-static volatile int ATTN;
-
-void swdp_interrupt(void) {
- ATTN++;
- if (write(2, "\b\b*INTERRUPT*\n", 16)) { /* do nothing */ }
-}
-
static pthread_mutex_t swd_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t swd_event = PTHREAD_COND_INITIALIZER;
static pthread_t swd_thread;
@@ -70,7 +63,7 @@ static unsigned swd_version = 0x0001;
static int swd_error = 0;
-int swdp_error(void) {
+static int _swdp_error(void) {
return swd_error;
}
@@ -219,6 +212,20 @@ static int process_reply(struct txn *t, u32 *data, int count) {
rxc--;
}
continue;
+ case CMD_JTAG_DATA:
+ //xprintf(XSWD, "JTAG DATA %d bits\n", n);
+ if (((n+31)/32) > rxc) {
+ xprintf(XSWD, "reply overrun (%d bits > %d words)\n", n, rxc);
+ return -1;
+ }
+ n = (n + 31) / 32;
+ while (n > 0) {
+ //xprintf(XSWD, "JTAG %08x\n", *data);
+ *(t->rx[rxp++]) = *data++;
+ rxc--;
+ n--;
+ }
+ continue;
case CMD_STATUS:
if (op) {
if (swd_verbose) {
@@ -442,14 +449,14 @@ int swdp_ap_read(u32 addr, u32 *value) {
return q_exec(&t);
}
-int swdp_ahb_read(u32 addr, u32 *value) {
+static int _swdp_ahb_read(u32 addr, u32 *value) {
struct txn t;
q_init(&t);
q_ahb_read(&t, addr, value);
return q_exec(&t);
}
-int swdp_ahb_write(u32 addr, u32 value) {
+static int _swdp_ahb_write(u32 addr, u32 value) {
struct txn t;
q_init(&t);
q_ahb_write(&t, addr, value);
@@ -494,7 +501,7 @@ int swdp_ahb_write32(u32 addr, u32 *in, int count) {
/* 10 txns overhead per 128 read txns - 126KB/s on 72MHz STM32F
* 8 txns overhead per 128 write txns - 99KB/s on 72MHz STM32F
*/
-int swdp_ahb_read32(u32 addr, u32 *out, int count) {
+static int _swdp_ahb_read32(u32 addr, u32 *out, int count) {
struct txn t;
while (count > 0) {
@@ -543,7 +550,7 @@ int swdp_ahb_read32(u32 addr, u32 *out, int count) {
return 0;
}
-int swdp_ahb_write32(u32 addr, u32 *in, int count) {
+static int _swdp_ahb_write32(u32 addr, u32 *in, int count) {
struct txn t;
while (count > 0) {
@@ -587,6 +594,7 @@ int swdp_ahb_write32(u32 addr, u32 *in, int count) {
}
#endif
+#if 0
int swdp_core_write(u32 n, u32 v) {
struct txn t;
q_init(&t);
@@ -738,6 +746,7 @@ int swdp_watchpoint_rw(unsigned n, u32 addr) {
int swdp_watchpoint_disable(unsigned n) {
return swdp_watchpoint(n, 0, DWT_FN_DISABLED);
}
+#endif
int swdp_bootloader(void) {
struct txn t;
@@ -746,7 +755,7 @@ int swdp_bootloader(void) {
return q_exec(&t);
}
-int swdp_reset(void) {
+static int _swdp_reset(void) {
struct txn t;
u32 n, idcode;
@@ -784,7 +793,7 @@ int swdp_reset(void) {
return 0;
}
-int swdp_clear_error(void) {
+static int _swdp_clear_error(void) {
if (swd_error == 0) {
return 0;
} else {
@@ -840,3 +849,30 @@ int swdp_open(void) {
pthread_create(&swd_thread, NULL, swd_reader, NULL);
return 0;
}
+
+int jtag_io(unsigned count, u32 *tms, u32 *tdi, u32 *tdo) {
+ struct txn t;
+ q_init(&t);
+ if (count > 32768)
+ return -1;
+ t.tx[t.txc++] = RSWD_MSG(CMD_JTAG_IO, 0, count);
+ count = (count + 31) / 32;
+ while (count > 0) {
+ t.tx[t.txc++] = *tms++;
+ t.tx[t.txc++] = *tdi++;
+ t.rx[t.rxc++] = tdo++;
+ count--;
+ }
+ return q_exec(&t);
+}
+
+debug_transport SWDP_TRANSPORT = {
+ .attach = _swdp_reset,
+ .error = _swdp_error,
+ .clear_error = _swdp_clear_error,
+ .mem_rd_32 = _swdp_ahb_read,
+ .mem_wr_32 = _swdp_ahb_write,
+ .mem_rd_32_c = _swdp_ahb_read32,
+ .mem_wr_32_c = _swdp_ahb_write32,
+};
+
diff --git a/tools/rswdp.h b/tools/rswdp.h
@@ -18,12 +18,21 @@
#ifndef _RSWDP_H__
#define _RSWDP_H__
-int swdp_ahb_read(u32 addr, u32 *value);
-int swdp_ahb_write(u32 addr, u32 value);
+int swdp_open(void);
+
+void swdp_enable_tracing(int yes);
+
+void swdp_target_reset(int enable);
+
+int swdp_bootloader(void);
+int swdp_set_clock(unsigned khz);
+int swo_set_clock(unsigned khz);
+
+int jtag_io(unsigned count, u32 *tms, u32 *tdi, u32 *tdo);
+
+void swdp_interrupt(void);
-/* bulk reads/writes (more efficient after ~3-4 words */
-int swdp_ahb_read32(u32 addr, u32 *out, int count);
-int swdp_ahb_write32(u32 addr, u32 *out, int count);
+/* these are now above the transport layer and should be renamed... */
/* return 0 when *addr != oldval, -1 on error, -2 on interrupt */
int swdp_ahb_wait_for_change(u32 addr, u32 oldval);
@@ -34,7 +43,6 @@ int swdp_core_resume(void);
/* return 0 when CPU halts, -1 if an error occurs, or -2 if interrupted */
int swdp_core_wait_for_halt(void);
-void swdp_interrupt(void);
/* access to CPU registers */
int swdp_core_read(u32 n, u32 *v);
@@ -47,22 +55,22 @@ int swdp_watchpoint_wr(unsigned n, u32 addr);
int swdp_watchpoint_rw(unsigned n, u32 addr);
int swdp_watchpoint_disable(unsigned n);
-/* attempt to clear any error state from previous transactions */
-/* return 0 if successful (or no error state existed) */
-int swdp_clear_error(void);
-int swdp_error(void);
-
-int swdp_reset(void);
-
-int swdp_open(void);
-
-void swdp_enable_tracing(int yes);
-
-void swdp_target_reset(int enable);
-
-int swdp_bootloader(void);
-int swdp_set_clock(unsigned khz);
-int swo_set_clock(unsigned khz);
+/* these are now provided by the transport layer */
+//int swdp_reset(void);
+//int swdp_error(void);
+//int swdp_clear_error(void);
+//int swdp_ahb_read(u32 addr, u32 *value);
+//int swdp_ahb_write(u32 addr, u32 value);
+// bulk reads/writes (more efficient after ~3-4 words
+// int swdp_ahb_read32(u32 addr, u32 *out, int count);
+// int swdp_ahb_write32(u32 addr, u32 *out, int count);
+#define swdp_reset debug_attach
+#define swdp_error debug_error
+#define swdp_clear_error debug_clear_error
+#define swdp_ahb_read mem_rd_32
+#define swdp_ahb_write mem_wr_32
+#define swdp_ahb_read32 mem_rd_32_c
+#define swdp_ahb_write32 mem_wr_32_c
#endif