diff options
author | Achin Gupta <achin.gupta@arm.com> | 2012-04-19 15:24:46 +0100 |
---|---|---|
committer | Dietmar Eggemann <dietmar.eggemann@arm.com> | 2012-05-23 12:44:35 +0100 |
commit | e829a12fee5ee36267e1c98cb6f82f3a918ad2aa (patch) | |
tree | bbe306a24a732b831694b078c218947e68ffa249 | |
parent | ecb8ff655a8c0ebbed6a269e484fd44e1f3816eb (diff) |
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.c | 332 |
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; +} |