summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAchin Gupta <achin.gupta@arm.com>2012-04-19 15:24:46 +0100
committerDietmar Eggemann <dietmar.eggemann@arm.com>2012-05-23 12:44:35 +0100
commite829a12fee5ee36267e1c98cb6f82f3a918ad2aa (patch)
treebbe306a24a732b831694b078c218947e68ffa249
parentecb8ff655a8c0ebbed6a269e484fd44e1f3816eb (diff)
downloadswitcher-e829a12fee5ee36267e1c98cb6f82f3a918ad2aa.tar.gz
Debug S&R cp14: Added support for cp14 based save/restore
1. If the processor implements Debug v7.1 then S&R takes place through the cp14 interface else through the memory mapped interface. 2. Helper functions to save and restore breakpoint and watchpoint context have been used to populate an array so that its possible use them through indices in a 'for' loop. 3. Debug context data structure is reused for S&R through both the memory mapped and the cp14 interface.
-rw-r--r--acsr/v7_c.c332
1 files changed, 326 insertions, 6 deletions
diff --git a/acsr/v7_c.c b/acsr/v7_c.c
index 1c23ac0..115b851 100644
--- a/acsr/v7_c.c
+++ b/acsr/v7_c.c
@@ -28,6 +28,7 @@
#include "bakery.h"
#include "helpers.h"
+#include "debug_helpers.h"
#include "context.h"
#define DIDR_VERSION_SHIFT 16
@@ -51,6 +52,12 @@
#define OSDLR_UNLOCKED 0x00000000
#define OSDLR_LOCKED 0x00000001
+#define DBGREG_BP_VAL 0x0
+#define DBGREG_WP_VAL 0x1
+#define DBGREG_BP_CTRL 0x2
+#define DBGREG_WP_CTRL 0x3
+#define DBGREG_BP_XVAL 0x4
+
typedef volatile struct { /* Registers Save? */
unsigned const didr; /* 0 Read only */
unsigned dscr_i; /* 1 ignore - use dscr_e instead */
@@ -105,12 +112,287 @@ typedef volatile struct { /* Registers Save?
unsigned const cid[4]; /* 1020-1023 Read only */
} debug_registers_t;
+typedef struct {
+ unsigned (*read)(void);
+ void (*write)(unsigned);
+} rw_ops;
+
+typedef struct {
+ rw_ops bvr;
+ rw_ops bcr;
+ rw_ops wvr;
+ rw_ops wcr;
+ rw_ops bxvr;
+} dbgreg_rw_ops;
+
+dbgreg_rw_ops dbgreg_rw_handlers[] = {
+ {
+ {read_dbg_bvr0, write_dbg_bvr0,},
+ {read_dbg_bcr0, write_dbg_bcr0,},
+ {read_dbg_wvr0, write_dbg_wvr0,},
+ {read_dbg_wcr0, write_dbg_wcr0,},
+ {read_dbg_bxvr0, write_dbg_bxvr0,},
+ },
+ {
+ {read_dbg_bvr1, write_dbg_bvr1,},
+ {read_dbg_bcr1, write_dbg_bcr1,},
+ {read_dbg_wvr1, write_dbg_wvr1,},
+ {read_dbg_wcr1, write_dbg_wcr1,},
+ {read_dbg_bxvr1, write_dbg_bxvr1,},
+ },
+ {
+ {read_dbg_bvr2, write_dbg_bvr2,},
+ {read_dbg_bcr2, write_dbg_bcr2,},
+ {read_dbg_wvr2, write_dbg_wvr2,},
+ {read_dbg_wcr2, write_dbg_wcr2,},
+ {read_dbg_bxvr2, write_dbg_bxvr2,},
+ },
+ {
+ {read_dbg_bvr3, write_dbg_bvr3,},
+ {read_dbg_bcr3, write_dbg_bcr3,},
+ {read_dbg_wvr3, write_dbg_wvr3,},
+ {read_dbg_wcr3, write_dbg_wcr3,},
+ {read_dbg_bxvr3, write_dbg_bxvr3,},
+ },
+ {
+ {read_dbg_bvr4, write_dbg_bvr4,},
+ {read_dbg_bcr4, write_dbg_bcr4,},
+ {read_dbg_wvr4, write_dbg_wvr4,},
+ {read_dbg_wcr4, write_dbg_wcr4,},
+ {read_dbg_bxvr4, write_dbg_bxvr4,},
+ },
+ {
+ {read_dbg_bvr5, write_dbg_bvr5,},
+ {read_dbg_bcr5, write_dbg_bcr5,},
+ {read_dbg_wvr5, write_dbg_wvr5,},
+ {read_dbg_wcr5, write_dbg_wcr5,},
+ {read_dbg_bxvr5, write_dbg_bxvr5,},
+ },
+ {
+ {read_dbg_bvr6, write_dbg_bvr6,},
+ {read_dbg_bcr6, write_dbg_bcr6,},
+ {read_dbg_wvr6, write_dbg_wvr6,},
+ {read_dbg_wcr6, write_dbg_wcr6,},
+ {read_dbg_bxvr6, write_dbg_bxvr6,},
+ },
+ {
+ {read_dbg_bvr7, write_dbg_bvr7,},
+ {read_dbg_bcr7, write_dbg_bcr7,},
+ {read_dbg_wvr7, write_dbg_wvr7,},
+ {read_dbg_wcr7, write_dbg_wcr7,},
+ {read_dbg_bxvr7, write_dbg_bxvr7,},
+ },
+ {
+ {read_dbg_bvr8, write_dbg_bvr8,},
+ {read_dbg_bcr8, write_dbg_bcr8,},
+ {read_dbg_wvr8, write_dbg_wvr8,},
+ {read_dbg_wcr8, write_dbg_wcr8,},
+ {read_dbg_bxvr8, write_dbg_bxvr8,},
+ },
+ {
+ {read_dbg_bvr9, write_dbg_bvr9,},
+ {read_dbg_bcr9, write_dbg_bcr9,},
+ {read_dbg_wvr9, write_dbg_wvr9,},
+ {read_dbg_wcr9, write_dbg_wcr9,},
+ {read_dbg_bxvr9, write_dbg_bxvr9,},
+ },
+ {
+ {read_dbg_bvr10, write_dbg_bvr10,},
+ {read_dbg_bcr10, write_dbg_bcr10,},
+ {read_dbg_wvr10, write_dbg_wvr10,},
+ {read_dbg_wcr10, write_dbg_wcr10,},
+ {read_dbg_bxvr10, write_dbg_bxvr10,},
+ },
+ {
+ {read_dbg_bvr11, write_dbg_bvr11,},
+ {read_dbg_bcr11, write_dbg_bcr11,},
+ {read_dbg_wvr11, write_dbg_wvr11,},
+ {read_dbg_wcr11, write_dbg_wcr11,},
+ {read_dbg_bxvr11, write_dbg_bxvr11,},
+ },
+ {
+ {read_dbg_bvr12, write_dbg_bvr12,},
+ {read_dbg_bcr12, write_dbg_bcr12,},
+ {read_dbg_wvr12, write_dbg_wvr12,},
+ {read_dbg_wcr12, write_dbg_wcr12,},
+ {read_dbg_bxvr12, write_dbg_bxvr12,},
+ },
+ {
+ {read_dbg_bvr13, write_dbg_bvr13,},
+ {read_dbg_bcr13, write_dbg_bcr13,},
+ {read_dbg_wvr13, write_dbg_wvr13,},
+ {read_dbg_wcr13, write_dbg_wcr13,},
+ {read_dbg_bxvr13, write_dbg_bxvr13,},
+ },
+ {
+ {read_dbg_bvr14, write_dbg_bvr14,},
+ {read_dbg_bcr14, write_dbg_bcr14,},
+ {read_dbg_wvr14, write_dbg_wvr14,},
+ {read_dbg_wcr14, write_dbg_wcr14,},
+ {read_dbg_bxvr14, write_dbg_bxvr14,},
+ },
+ {
+ {read_dbg_bvr15, write_dbg_bvr15,},
+ {read_dbg_bcr15, write_dbg_bcr15,},
+ {read_dbg_wvr15, write_dbg_wvr15,},
+ {read_dbg_wcr15, write_dbg_wcr15,},
+ {read_dbg_bxvr15, write_dbg_bxvr15,},
+ },
+};
+
+static void restore_bp_reg(debug_registers_t *dbg, unsigned index, unsigned type)
+{
+ switch (type) {
+ case DBGREG_WP_VAL:
+ dbgreg_rw_handlers[index].wvr.write(dbg->wvr[index]);
+ break;
+ case DBGREG_WP_CTRL:
+ dbgreg_rw_handlers[index].wcr.write(dbg->wcr[index]);
+ break;
+ case DBGREG_BP_XVAL:
+ dbgreg_rw_handlers[index].bxvr.write(dbg->bxvr[index]);
+ break;
+ case DBGREG_BP_VAL:
+ dbgreg_rw_handlers[index].bvr.write(dbg->bvr[index]);
+ break;
+ case DBGREG_BP_CTRL:
+ dbgreg_rw_handlers[index].bcr.write(dbg->bcr[index]);
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+static void save_bp_reg(debug_registers_t *dbg, unsigned index, unsigned type)
+{
+ switch (type) {
+ case DBGREG_WP_VAL:
+ dbg->wvr[index] = dbgreg_rw_handlers[index].wvr.read();
+ break;
+ case DBGREG_WP_CTRL:
+ dbg->wcr[index] = dbgreg_rw_handlers[index].wcr.read();
+ break;
+ case DBGREG_BP_XVAL:
+ dbg->bxvr[index] = dbgreg_rw_handlers[index].bxvr.read();
+ break;
+ case DBGREG_BP_VAL:
+ dbg->bvr[index] = dbgreg_rw_handlers[index].bvr.read();
+ break;
+ case DBGREG_BP_CTRL:
+ dbg->bcr[index] = dbgreg_rw_handlers[index].bcr.read();
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+static void sr_bp_context(debug_registers_t *dbg, unsigned bp_type, unsigned op)
+{
+ unsigned num_bps, num_ctx_cmps, num_wps, didr;
+ unsigned index = 0, max_index = 0;
+
+ didr = read_dbg_didr();
+ num_bps = (didr >> 24) & 0xf;
+ num_ctx_cmps = (didr >> 20) & 0xf;
+ num_wps = (didr >> 28) & 0xf;
+
+ switch (bp_type) {
+ case DBGREG_WP_VAL:
+ case DBGREG_WP_CTRL:
+ max_index = num_wps;
+ break;
+ case DBGREG_BP_XVAL:
+ index = num_bps - num_ctx_cmps;
+ case DBGREG_BP_VAL:
+ case DBGREG_BP_CTRL:
+ max_index = num_bps;
+ break;
+ default:
+ break;
+ }
+
+ for (; index <= max_index; index++)
+ if (op)
+ save_bp_reg(dbg, index, bp_type);
+ else
+ restore_bp_reg(dbg, index, bp_type);
+ return;
+}
+
+static void save_v7_debug_cp14(unsigned * context)
+{
+ debug_registers_t *dbg = (void *) context;
+ unsigned virtext_present = (read_dbg_devid() >> 16) & 0xf;
+
+ /*
+ * Prevent updates to the debug registers during a S&R operation
+ */
+ write_dbg_oslar(OSLAR_LOCKED);
+
+ dbg->dtrrx_e = read_dbg_dtrrxext();
+ dbg->dtrtx_e = read_dbg_dtrtxext();
+ dbg->dscr_e = read_dbg_dscrext();
+ dbg->wfar = read_dbg_wfar();
+ dbg->vcr = read_dbg_vcr();
+ dbg->claimclr = read_dbg_claimclr();
+
+ if (virtext_present)
+ sr_bp_context(dbg, DBGREG_BP_XVAL, 1);
+
+ sr_bp_context(dbg, DBGREG_BP_VAL, 1);
+ sr_bp_context(dbg, DBGREG_BP_CTRL, 1);
+ sr_bp_context(dbg, DBGREG_WP_VAL, 1);
+ sr_bp_context(dbg, DBGREG_WP_CTRL, 1);
+
+ write_dbg_osdlr(OSDLR_LOCKED);
+
+ return;
+}
+
+static void restore_v7_debug_cp14(unsigned * context)
+{
+ debug_registers_t *dbg = (void *) context;
+ unsigned virtext_present = (read_dbg_devid() >> 16) & 0xf;
+
+ /*
+ * Prevent updates to the debug registers during a S&R operation
+ */
+ write_dbg_oslar(OSLAR_LOCKED);
+
+ write_dbg_dtrrxext(dbg->dtrrx_e);
+ write_dbg_dtrtxext(dbg->dtrtx_e);
+ write_dbg_dscrext(dbg->dscr_e);
+ write_dbg_wfar(dbg->wfar);
+ write_dbg_vcr(dbg->vcr);
+ write_dbg_claimset(dbg->claimclr);
+
+ if (virtext_present)
+ sr_bp_context(dbg, DBGREG_BP_XVAL, 0);
+
+ sr_bp_context(dbg, DBGREG_BP_VAL, 0);
+ sr_bp_context(dbg, DBGREG_BP_CTRL, 0);
+ sr_bp_context(dbg, DBGREG_WP_VAL, 0);
+ sr_bp_context(dbg, DBGREG_WP_CTRL, 0);
+ isb();
+
+ /*
+ * Unlock access to the debug registers
+ */
+ write_dbg_oslar(OSLAR_UNLOCKED);
+
+ return;
+}
+
debug_registers_t *read_debug_address(void)
{
unsigned drar, dsar;
- drar = read_drar();
- dsar = read_dsar();
+ drar = read_dbg_drar();
+ dsar = read_dbg_dsar();
if (!(drar & DRAR_VALID_MASK)
|| !(dsar & DSAR_VALID_MASK)) {
@@ -128,7 +410,7 @@ debug_registers_t *read_debug_address(void)
* - OSDLR is NOT locked, or the debugger would not work properly
*/
-void save_v7_debug(unsigned * context)
+static void save_v7_debug_mmapped(unsigned * context)
{
debug_registers_t *dbg = (void *)read_debug_address();
debug_context_t *ctx = (void *)context;
@@ -177,11 +459,11 @@ void save_v7_debug(unsigned * context)
* Once we have done this, debug becomes inaccessible.
*/
if (v71) {
- write_osdlr(OSDLR_LOCKED);
+ write_dbg_osdlr(OSDLR_LOCKED);
}
}
-void restore_v7_debug(unsigned * context)
+static void restore_v7_debug_mmapped(unsigned * context)
{
debug_registers_t *dbg = (void *)read_debug_address();
debug_context_t *ctx = (void *)context;
@@ -207,7 +489,7 @@ void restore_v7_debug(unsigned * context)
* (If the CPU has not actually power-cycled, osdlr may not be reset).
*/
if (v71) {
- write_osdlr(OSDLR_UNLOCKED);
+ write_dbg_osdlr(OSDLR_UNLOCKED);
}
/*
@@ -246,3 +528,41 @@ void restore_v7_debug(unsigned * context)
/* Disable write access to registers */
dbg->lar = LAR_LOCKED;
}
+
+void save_v7_debug(unsigned * context)
+{
+ unsigned v71 = 0, didr = read_dbg_didr();
+
+ v71 =(((didr >> DIDR_VERSION_SHIFT) & DIDR_VERSION_MASK) ==
+ DIDR_VERSION_7_1);
+
+ /*
+ * TODO: Code for saving the v7.0 Debug context through the
+ * cp14 interface has not been implemented as yet.
+ */
+ if(v71)
+ save_v7_debug_cp14(context);
+ else
+ save_v7_debug_mmapped(context);
+
+ return;
+}
+
+void restore_v7_debug(unsigned * context)
+{
+ unsigned v71 = 0, didr = read_dbg_didr();
+
+ v71 =(((didr >> DIDR_VERSION_SHIFT) & DIDR_VERSION_MASK) ==
+ DIDR_VERSION_7_1);
+
+ /*
+ * TODO: Code for restoring the v7.0 Debug context through the
+ * cp14 interface has not been implemented as yet.
+ */
+ if(v71)
+ restore_v7_debug_cp14(context);
+ else
+ restore_v7_debug_mmapped(context);
+
+ return;
+}