aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cortexm3.c113
-rw-r--r--src/gdb_main.c58
-rw-r--r--src/include/target.h1
3 files changed, 132 insertions, 40 deletions
diff --git a/src/cortexm3.c b/src/cortexm3.c
index 645fe3e..0dbb722 100644
--- a/src/cortexm3.c
+++ b/src/cortexm3.c
@@ -46,6 +46,7 @@ static char cm3_driver_str[] = "ARM Cortex-M3";
#define CM3_SCS_BASE (CM3_PPB_BASE + 0xE000)
#define CM3_AIRCR (CM3_SCS_BASE + 0xD0C)
+#define CM3_CFSR (CM3_SCS_BASE + 0xD28)
#define CM3_HFSR (CM3_SCS_BASE + 0xD2C)
#define CM3_DFSR (CM3_SCS_BASE + 0xD30)
#define CM3_DHCSR (CM3_SCS_BASE + 0xDF0)
@@ -190,6 +191,54 @@ static struct wp_unit_s {
/* Breakpoint unit status */
static uint32_t hw_breakpoint[6];
+/* Register number tables */
+static uint32_t regnum_v7m[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* standard r0-r15 */
+ 0x10, /* xpsr */
+ 0x11, /* msp */
+ 0x12, /* psp */
+ 0x14 /* special */
+};
+#if 0
+/* XXX: need some way for a specific CPU to indicate it has FP registers */
+static uint32_t regnum_v7mf[] = {
+ 0x21, /* fpscr */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* s0-s7 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* s8-s15 */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* s16-s23 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* s24-s31 */
+};
+#endif
+
+static const char tdesc_armv7m[] =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+ "<target>"
+ " <architecture>arm</architecture>"
+ " <feature name=\"org.gnu.gdb.arm.m-profile\">"
+ " <reg name=\"r0\" bitsize=\"32\"/>"
+ " <reg name=\"r1\" bitsize=\"32\"/>"
+ " <reg name=\"r2\" bitsize=\"32\"/>"
+ " <reg name=\"r3\" bitsize=\"32\"/>"
+ " <reg name=\"r4\" bitsize=\"32\"/>"
+ " <reg name=\"r5\" bitsize=\"32\"/>"
+ " <reg name=\"r6\" bitsize=\"32\"/>"
+ " <reg name=\"r7\" bitsize=\"32\"/>"
+ " <reg name=\"r8\" bitsize=\"32\"/>"
+ " <reg name=\"r9\" bitsize=\"32\"/>"
+ " <reg name=\"r10\" bitsize=\"32\"/>"
+ " <reg name=\"r11\" bitsize=\"32\"/>"
+ " <reg name=\"r12\" bitsize=\"32\"/>"
+ " <reg name=\"sp\" bitsize=\"32\" type=\"data_ptr\"/>"
+ " <reg name=\"lr\" bitsize=\"32\" type=\"code_ptr\"/>"
+ " <reg name=\"pc\" bitsize=\"32\" type=\"code_ptr\"/>"
+ " <reg name=\"xpsr\" bitsize=\"32\"/>"
+ " <reg name=\"msp\" bitsize=\"32\" save-restore=\"no\" type=\"data_ptr\"/>"
+ " <reg name=\"psp\" bitsize=\"32\" save-restore=\"no\" type=\"data_ptr\"/>"
+ " <reg name=\"special\" bitsize=\"32\" save-restore=\"no\"/>"
+ " </feature>"
+ "</target>";
+
int
cm3_probe(struct target_s *target)
{
@@ -199,6 +248,7 @@ cm3_probe(struct target_s *target)
target->detach = cm3_detach;
/* Should probe here to make sure it's Cortex-M3 */
+ target->tdesc = tdesc_armv7m;
target->regs_read = cm3_regs_read;
target->regs_write = cm3_regs_write;
target->pc_write = cm3_pc_write;
@@ -208,7 +258,7 @@ cm3_probe(struct target_s *target)
target->halt_wait = cm3_halt_wait;
target->halt_resume = cm3_halt_resume;
target->fault_unwind = cm3_fault_unwind;
- target->regs_size = 16<<2;
+ target->regs_size = sizeof(regnum_v7m); /* XXX: detect FP extension */
if(stm32_probe(target) == 0) return 0;
if(stm32f4_probe(target) == 0) return 0;
@@ -282,15 +332,21 @@ cm3_regs_read(struct target_s *target, void *data)
{
struct target_ap_s *t = (void *)target;
uint32_t *regs = data;
- int i;
+ unsigned i;
/* FIXME: Describe what's really going on here */
adiv5_ap_write(t->ap, 0x00, 0xA2000052);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, 0xE000EDF0);
- adiv5_ap_write(t->ap, 0x14, 0); /* Required to switch banks */
+
+ /* Map the banked data registers (0x10-0x1c) to the
+ * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, CM3_DHCSR);
+
+ /* Walk the regnum_v7m array, reading the registers it
+ * calls out. */
+ adiv5_ap_write(t->ap, 0x14, regnum_v7m[0]); /* Required to switch banks */
*regs++ = adiv5_dp_read_ap(t->ap->dp, 0x18);
- for(i = 1; i < 16; i++) {
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, i);
+ for(i = 1; i < sizeof(regnum_v7m) / 4; i++) {
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, regnum_v7m[i]);
*regs++ = adiv5_dp_read_ap(t->ap->dp, 0x18);
}
@@ -306,12 +362,18 @@ cm3_regs_write(struct target_s *target, const void *data)
/* FIXME: Describe what's really going on here */
adiv5_ap_write(t->ap, 0x00, 0xA2000052);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, 0xE000EDF0);
+
+ /* Map the banked data registers (0x10-0x1c) to the
+ * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, CM3_DHCSR);
+
+ /* Walk the regnum_v7m array, writing the registers it
+ * calls out. */
adiv5_ap_write(t->ap, 0x18, *regs++); /* Required to switch banks */
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000);
- for(i = 1; i < 16; i++) {
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_v7m[0]);
+ for(i = 1; i < sizeof(regnum_v7m) / 4; i++) {
adiv5_dp_low_access(t->ap->dp, 1, 0, 0x18, *regs++);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, i | 0x10000);
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_v7m[i]);
}
return 0;
@@ -395,27 +457,34 @@ static int cm3_fault_unwind(struct target_s *target)
struct target_ap_s *t = (void *)target;
uint32_t dfsr = adiv5_ap_mem_read(t->ap, CM3_DFSR);
uint32_t hfsr = adiv5_ap_mem_read(t->ap, CM3_HFSR);
+ uint32_t cfsr = adiv5_ap_mem_read(t->ap, CM3_CFSR);
adiv5_ap_mem_write(t->ap, CM3_DFSR, dfsr);/* write back to reset */
adiv5_ap_mem_write(t->ap, CM3_HFSR, hfsr);/* write back to reset */
- /* We check for FORCED in the HardFault Status Register to avoid
- * catching core resets */
- if((dfsr & CM3_DFSR_VCATCH) && (hfsr & CM3_HFSR_FORCED)) {
+ adiv5_ap_mem_write(t->ap, CM3_CFSR, cfsr);/* write back to reset */
+ /* We check for FORCED in the HardFault Status Register or
+ * for a configurable fault to avoid catching core resets */
+ if((dfsr & CM3_DFSR_VCATCH) && ((hfsr & CM3_HFSR_FORCED) || cfsr)) {
/* Unwind exception */
- uint32_t regs[16];
+ uint32_t regs[target->regs_size];
uint32_t stack[8];
+ uint32_t retcode, framesize;
/* Read registers for post-exception stack pointer */
target_regs_read(target, regs);
+ /* save retcode currently in lr */
+ retcode = regs[14];
/* Read stack for pre-exception registers */
target_mem_read_words(target, stack, regs[13], sizeof(stack));
- regs[13] += sizeof(stack); /* Adjust SP for pop */
- regs[0] = stack[0];
- regs[1] = stack[1];
- regs[2] = stack[2];
- regs[3] = stack[3];
- regs[12] = stack[4];
- regs[14] = stack[5];
- regs[15] = stack[6];
+ regs[14] = stack[5]; /* restore LR to pre-exception state */
+ regs[15] = stack[6]; /* restore PC to pre-exception state */
+
+ /* adjust stack to pop exception state */
+ framesize = (retcode & (1<<4)) ? 0x68 : 0x20; /* check for basic vs. extended frame */
+ if (stack[7] & (1<<9)) /* check for stack alignment fixup */
+ framesize += 4;
+ regs[13] += framesize;
+
/* FIXME: stack[7] contains xPSR when this is supported */
+ /* although, if we caught the exception it will be unchanged */
/* Reset exception state to allow resuming from restored
* state.
diff --git a/src/gdb_main.c b/src/gdb_main.c
index e890999..0655d63 100644
--- a/src/gdb_main.c
+++ b/src/gdb_main.c
@@ -56,8 +56,6 @@ static unsigned char pbuf[BUF_SIZE];
static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, int len);
-uint32_t arm_regs[16];
-
void
gdb_main(void)
{
@@ -74,9 +72,10 @@ gdb_main(void)
switch(pbuf[0]) {
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
+ uint32_t arm_regs[cur_target->regs_size];
ERROR_IF_NO_TARGET();
target_regs_read(cur_target, (void*)arm_regs);
- gdb_putpacket(hexify(pbuf, (void*)arm_regs, sizeof(arm_regs)), sizeof(arm_regs)*2);
+ gdb_putpacket(hexify(pbuf, (void*)arm_regs, cur_target->regs_size), cur_target->regs_size * 2);
break;
}
case 'm': { /* 'm addr,len': Read len bytes from addr */
@@ -98,13 +97,14 @@ gdb_main(void)
free(mem);
break;
}
- case 'G': /* 'G XX': Write general registers */
+ case 'G': { /* 'G XX': Write general registers */
+ uint32_t arm_regs[cur_target->regs_size];
ERROR_IF_NO_TARGET();
unhexify((void*)arm_regs, &pbuf[1], cur_target->regs_size);
target_regs_write(cur_target, arm_regs);
gdb_putpacket("OK", 2);
break;
-
+ }
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
unsigned long addr, len;
int hex;
@@ -292,6 +292,27 @@ gdb_main(void)
}
}
+static void
+handle_q_string_reply(const char *str, const char *param)
+{
+ unsigned long addr, len;
+
+ if (sscanf(param, "%08lX,%08lX", &addr, &len) != 2) {
+ gdb_putpacketz("E01");
+ return;
+ }
+ if (addr < strlen (str)) {
+ uint8_t reply[len+2];
+ reply[0] = 'm';
+ strncpy (reply + 1, &str[addr], len);
+ if(len > strlen(&str[addr]))
+ len = strlen(&str[addr]);
+ gdb_putpacket(reply, len + 1);
+ } else if (addr == strlen (str)) {
+ gdb_putpacketz("l");
+ } else
+ gdb_putpacketz("E01");
+}
static void
handle_q_packet(char *packet, int len)
@@ -314,12 +335,10 @@ handle_q_packet(char *packet, int len)
} else if (!strncmp (packet, "qSupported", 10)) {
/* Query supported protocol features */
- gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+", BUF_SIZE);
+ gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+:qXfer:features:read+", BUF_SIZE);
} else if (strncmp (packet, "qXfer:memory-map:read::", 23) == 0) {
/* Read target XML memory map */
- unsigned long addr, len;
- sscanf(packet+23, "%08lX,%08lX", &addr, &len);
if((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = last_target;
@@ -329,17 +348,20 @@ handle_q_packet(char *packet, int len)
gdb_putpacketz("E01");
return;
}
- if (addr < strlen (cur_target->xml_mem_map)) {
- uint8_t reply[len+2];
- reply[0] = 'm';
- strncpy (reply + 1, &cur_target->xml_mem_map[addr], len);
- if(len > strlen(&cur_target->xml_mem_map[addr]))
- len = strlen(&cur_target->xml_mem_map[addr]);
- gdb_putpacket(reply, len + 1);
- } else if (addr == strlen (cur_target->xml_mem_map)) {
- gdb_putpacketz("l");
- } else
+ handle_q_string_reply(cur_target->xml_mem_map, packet + 23);
+
+ } else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
+ /* Read target description */
+ if((!cur_target) && last_target) {
+ /* Attach to last target if detached. */
+ cur_target = last_target;
+ target_attach(cur_target);
+ }
+ if((!cur_target) || (!cur_target->tdesc)) {
gdb_putpacketz("E01");
+ return;
+ }
+ handle_q_string_reply(cur_target->tdesc, packet + 31);
} else gdb_putpacket("", 0);
}
diff --git a/src/include/target.h b/src/include/target.h
index 030b41e..1ff61b5 100644
--- a/src/include/target.h
+++ b/src/include/target.h
@@ -136,6 +136,7 @@ typedef struct target_s {
/* Register access functions */
int regs_size;
+ const char *tdesc;
int (*regs_read)(struct target_s *target, void *data);
int (*regs_write)(struct target_s *target, const void *data);