X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Farm_dpm.c;h=3e8180c36db8d8d73baf8c4227609432d478903a;hb=2830008be0f782f22e09f6ecd1764e168560de40;hp=0c84be5440cef355ceeff28207cd3697afa56e90;hpb=84a0bb4a3c3c883b22f95abc7f1428faef3936f1;p=openocd.git diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 0c84be5440..3e8180c36d 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -21,6 +21,7 @@ #include "arm.h" #include "arm_dpm.h" +#include "armv8_dpm.h" #include #include "register.h" #include "breakpoints.h" @@ -130,11 +131,11 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) return retval; } - -static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +/* just read the register -- rely on the core mode being right */ +static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { uint32_t value; - int retval = ERROR_FAIL; + int retval; switch (regnum) { case 0 ... 14: @@ -165,8 +166,8 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum) /* core-specific ... ? */ LOG_WARNING("Jazelle PC adjustment unknown"); break; - case ARM_STATE_AARCH64: - LOG_ERROR("AARCH64: 32bit read requested"); + default: + LOG_WARNING("unknow core state"); break; } break; @@ -190,57 +191,10 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum) return retval; } -static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) -{ - uint64_t value; - uint32_t i; - int retval = ERROR_FAIL; - - switch (regnum) { - case 0 ... 30: - i = 0xd5130400 + regnum; /* msr dbgdtr_el0,reg */ - retval = dpm->instr_read_data_dcc_64(dpm, i, &value); - break; - case 31: /* SP */ - i = 0x910003e0; - retval = dpm->instr_read_data_r0_64(dpm, i, &value); - break; - case 32: /* PC */ - i = 0xd53b4520; - retval = dpm->instr_read_data_r0_64(dpm, i, &value); - break; - case 33: /* CPSR */ - i = 0xd53b4500; - retval = dpm->instr_read_data_r0_64(dpm, i, &value); - break; - - default: - break; - } - - if (retval == ERROR_OK) { - buf_set_u64(r->value, 0, 64, value); - r->valid = true; - r->dirty = false; - LOG_DEBUG("READ: %s, %16.16llx", r->name, (long long)value); - } - - return retval; -} - - -/* just read the register -- rely on the core mode being right */ -static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) -{ - if (r->size == 64) - return dpm_read_reg64(dpm, r, regnum); - else - return dpm_read_reg32(dpm, r, regnum); -} - -static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +/* just write the register -- rely on the core mode being right */ +static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { - int retval = ERROR_FAIL; + int retval; uint32_t value = buf_get_u32(r->value, 0, 32); switch (regnum) { @@ -290,46 +244,19 @@ static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r) return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value); } -static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) -{ - int retval = ERROR_FAIL; - uint32_t i; - uint64_t value = buf_get_u64(r->value, 0, 64); - - switch (regnum) { - case 0 ... 30: - i = 0xd5330400 + regnum; - retval = dpm->instr_write_data_dcc(dpm, i, value); - break; - - default: - break; - } - - if (retval == ERROR_OK) { - r->dirty = false; - LOG_DEBUG("WRITE: %s, %16.16llx", r->name, (unsigned long long)value); - } - - return retval; -} - -/* just write the register -- rely on the core mode being right */ -static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) -{ - if (r->size == 64) - return dpm_write_reg64(dpm, r, regnum); - else - return dpm_write_reg32(dpm, r, regnum); -} - -static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm) +/** + * Read basic registers of the the current context: R0 to R15, and CPSR; + * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). + * In normal operation this is called on entry to halting debug state, + * possibly after some other operations supporting restore of debug state + * or making sure the CPU is fully idle (drain write buffer, etc). + */ +int arm_dpm_read_current_registers(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; - uint32_t cpsr, instr, core_regs; + uint32_t cpsr; int retval; struct reg *r; - enum arm_state core_state = arm->core_state; retval = dpm->prepare(dpm); if (retval != ERROR_OK) @@ -344,22 +271,16 @@ static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm) } r->dirty = true; - if (core_state == ARM_STATE_AARCH64) - instr = 0xd53b4500; /* mrs x0, dspsr_el0 */ - else - instr = ARMV4_5_MRS(0, 0); - retval = dpm->instr_read_data_r0(dpm, instr, &cpsr); + retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr); if (retval != ERROR_OK) goto fail; /* update core mode and state, plus shadow mapping for R8..R14 */ arm_set_cpsr(arm, cpsr); - core_regs = arm->core_cache->num_regs; - /* REVISIT we can probably avoid reading R1..R14, saving time... */ - for (unsigned i = 1; i < core_regs; i++) { - r = dpm->arm_reg_current(arm, i); + for (unsigned i = 1; i < 16; i++) { + r = arm_reg_current(arm, i); if (r->valid) continue; @@ -380,23 +301,6 @@ fail: return retval; } -/** - * Read basic registers of the the current context: R0 to R15, and CPSR; - * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). - * In normal operation this is called on entry to halting debug state, - * possibly after some other operations supporting restore of debug state - * or making sure the CPU is fully idle (drain write buffer, etc). - */ -int arm_dpm_read_current_registers(struct arm_dpm *dpm) -{ - return arm_dpm_read_current_registers_i(dpm); -} - -int arm_dpm_read_current_registers_64(struct arm_dpm *dpm) -{ - return arm_dpm_read_current_registers_i(dpm); -} - /* Avoid needless I/O ... leave breakpoints and watchpoints alone * unless they're removed, or need updating because of single-stepping * or running debugger code. @@ -445,14 +349,59 @@ done: static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp); - -static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm) +/** + * Writes all modified core registers for all processor modes. In normal + * operation this is called on exit from halting debug state. + * + * @param dpm: represents the processor + * @param bpwp: true ensures breakpoints and watchpoints are set, + * false ensures they are cleared + */ +int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) { struct arm *arm = dpm->arm; struct reg_cache *cache = arm->core_cache; int retval; bool did_write; + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + /* If we're managing hardware breakpoints for this core, enable + * or disable them as requested. + * + * REVISIT We don't yet manage them for ANY cores. Eventually + * we should be able to assume we handle them; but until then, + * cope with the hand-crafted breakpoint code. + */ + if (arm->target->type->add_breakpoint == dpm_add_breakpoint) { + for (unsigned i = 0; i < dpm->nbp; i++) { + struct dpm_bp *dbp = dpm->dbp + i; + struct breakpoint *bp = dbp->bp; + + retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, + bp ? &bp->set : NULL); + if (retval != ERROR_OK) + goto done; + } + } + + /* enable/disable watchpoints */ + for (unsigned i = 0; i < dpm->nwp; i++) { + struct dpm_wp *dwp = dpm->dwp + i; + struct watchpoint *wp = dwp->wp; + + retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, + wp ? &wp->set : NULL); + if (retval != ERROR_OK) + goto done; + } + + /* NOTE: writes to breakpoint and watchpoint registers might + * be queued, and need (efficient/batched) flushing later. + */ + /* Scan the registers until we find one that's both dirty and * eligible for flushing. Flush that and everything else that * shares the same core mode setting. Typically this won't @@ -556,106 +505,6 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm) goto done; cache->reg_list[0].dirty = false; -done: - return retval; -} - -static int arm_dpm_write_dirty_registers_64(struct arm_dpm *dpm) -{ - struct arm *arm = dpm->arm; - struct reg_cache *cache = arm->core_cache; - int retval; - - /* Scan the registers until we find one that's both dirty and - * eligible for flushing. Flush that and everything else that - * shares the same core mode setting. Typically this won't - * actually find anything to do... - */ - - /* check everything except our scratch register R0 */ - for (unsigned i = 1; i < 32; i++) { - struct arm_reg *r; - unsigned regnum; - - if (!cache->reg_list[i].dirty) - continue; - - r = cache->reg_list[i].arch_info; - regnum = r->num; - retval = dpm_write_reg(dpm, - &cache->reg_list[i], - regnum); - if (retval != ERROR_OK) - goto done; - } - - /* flush R0 -- it's *very* dirty by now */ - retval = dpm_write_reg(dpm, &cache->reg_list[0], 0); - if (retval != ERROR_OK) - goto done; - cache->reg_list[0].dirty = false; - -done: - return retval; -} - -/** - * Writes all modified core registers for all processor modes. In normal - * operation this is called on exit from halting debug state. - * - * @param dpm: represents the processor - * @param bpwp: true ensures breakpoints and watchpoints are set, - * false ensures they are cleared - */ -int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) -{ - struct arm *arm = dpm->arm; - struct reg_cache *cache = arm->core_cache; - int retval; - - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - - /* If we're managing hardware breakpoints for this core, enable - * or disable them as requested. - * - * REVISIT We don't yet manage them for ANY cores. Eventually - * we should be able to assume we handle them; but until then, - * cope with the hand-crafted breakpoint code. - */ - if (arm->target->type->add_breakpoint == dpm_add_breakpoint) { - for (unsigned i = 0; i < dpm->nbp; i++) { - struct dpm_bp *dbp = dpm->dbp + i; - struct breakpoint *bp = dbp->bp; - - retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); - if (retval != ERROR_OK) - goto done; - } - } - - /* enable/disable watchpoints */ - for (unsigned i = 0; i < dpm->nwp; i++) { - struct dpm_wp *dwp = dpm->dwp + i; - struct watchpoint *wp = dwp->wp; - - retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); - if (retval != ERROR_OK) - goto done; - } - - /* NOTE: writes to breakpoint and watchpoint registers might - * be queued, and need (efficient/batched) flushing later. - */ - - if (cache->reg_list[0].size == 64) - retval = arm_dpm_write_dirty_registers_64(dpm); - else - retval = arm_dpm_write_dirty_registers_32(dpm); - /* (void) */ dpm->finish(dpm); done: return retval; @@ -1081,20 +930,16 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { - case 6: /* Data abort (v6 only) */ - case 7: /* Prefetch abort (v6 only) */ - /* FALL THROUGH -- assume a v6 core in abort mode */ - case 0: /* HALT request from debugger */ - case 4: /* EDBGRQ */ + case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ + case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ target->debug_reason = DBG_REASON_DBGRQ; break; - case 1: /* HW breakpoint */ - case 3: /* SW BKPT */ - case 5: /* vector catch */ + case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ + case DSCR_ENTRY_BKPT_INSTR: /* vector catch */ target->debug_reason = DBG_REASON_BREAKPOINT; break; - case 2: /* asynch watchpoint */ - case 10:/* precise watchpoint */ + case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ + case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ target->debug_reason = DBG_REASON_WATCHPOINT; break; default: @@ -1119,16 +964,15 @@ int arm_dpm_setup(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct target *target = arm->target; - struct reg_cache *cache; + struct reg_cache *cache = 0; arm->dpm = dpm; /* register access setup */ arm->full_context = arm_dpm_full_context; - arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg; - arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg; + arm->read_core_reg = arm_dpm_read_core_reg; + arm->write_core_reg = arm_dpm_write_core_reg; - /* avoid duplicating the register cache */ if (arm->core_cache == NULL) { cache = arm_build_reg_cache(target, arm); if (!cache) @@ -1151,20 +995,10 @@ int arm_dpm_setup(struct arm_dpm *dpm) target->type->add_watchpoint = dpm_add_watchpoint; target->type->remove_watchpoint = dpm_remove_watchpoint; - - if (dpm->arm_reg_current == 0) - dpm->arm_reg_current = arm_reg_current; - /* FIXME add vector catch support */ - if (arm->core_state == ARM_STATE_AARCH64) { - dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); - dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); - } else { - dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf); - dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf); - } - + dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); + dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);