This is an automated email from Gerrit. David Ung (dav...@nvidia.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2500
-- gerrit commit 1de2b7ab0aac5142693df2404900647cd0076770 Author: David Ung <dav...@nvidia.com> Date: Fri Jan 16 18:04:06 2015 -0800 arm_dpm: Add 64bit register handling. Add various function to read/write ARMv8 registers. Change-Id: I16f2829bdd0e87b050a51e414ff675d5c21bcbae Signed-off-by: David Ung <dav...@nvidia.com> diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 7f31833..e4c2b68 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -132,8 +132,8 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) 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) + +static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { uint32_t value; int retval; @@ -189,8 +189,55 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) 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) +static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +{ + uint64_t value; + uint32_t i; + int retval; + + 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) { int retval; uint32_t value = buf_get_u32(r->value, 0, 32); @@ -230,17 +277,43 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) 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) +static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +{ + int retval; + 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, int arch_mode) { struct arm *arm = dpm->arm; - uint32_t cpsr; + uint32_t cpsr, instr, core_regs; int retval; struct reg *r; @@ -257,16 +330,22 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) } r->dirty = true; - retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr); + if (arch_mode == 64) + instr = 0xd53b4500; /* mrs x0, dspsr_el0 */ + else + instr = ARMV4_5_MRS(0, 0); + retval = dpm->instr_read_data_r0(dpm, instr, &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 < 16; i++) { - r = arm_reg_current(arm, i); + for (unsigned i = 1; i < core_regs; i++) { + r = dpm->arm_reg_current(arm, i); if (r->valid) continue; @@ -287,6 +366,23 @@ 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, 32); +} + +int arm_dpm_read_current_registers_64(struct arm_dpm *dpm) +{ + return arm_dpm_read_current_registers_i(dpm, 64); +} + /* Avoid needless I/O ... leave breakpoints and watchpoints alone * unless they're removed, or need updating because of single-stepping * or running debugger code. @@ -946,8 +1042,8 @@ int arm_dpm_setup(struct arm_dpm *dpm, int arch_mode) /* register access setup */ arm->full_context = arm_dpm_full_context; - arm->read_core_reg = arm_dpm_read_core_reg; - arm->write_core_reg = arm_dpm_write_core_reg; + 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; if (arch_mode == 64) ; @@ -974,12 +1070,21 @@ int arm_dpm_setup(struct arm_dpm *dpm, int arch_mode) 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 */ - dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); - dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); + if (arch_mode == 64) { + 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->nwp = 1 + ((dpm->didr >> 28) & 0xf); + dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); if (!dpm->dbp || !dpm->dwp) { diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index 6c56ac3..1e50395 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -88,10 +88,19 @@ struct arm_dpm { int (*instr_read_data_dcc)(struct arm_dpm *, uint32_t opcode, uint32_t *data); + int (*instr_read_data_dcc_64)(struct arm_dpm *, + uint32_t opcode, uint64_t *data); + /** Runs one instruction, reading data from r0 after execution. */ int (*instr_read_data_r0)(struct arm_dpm *, uint32_t opcode, uint32_t *data); + int (*instr_read_data_r0_64)(struct arm_dpm *, + uint32_t opcode, uint64_t *data); + + struct reg *(*arm_reg_current)(struct arm *arm, + unsigned regnum); + /* BREAKPOINT/WATCHPOINT SUPPORT */ /** @@ -133,6 +142,7 @@ int arm_dpm_setup(struct arm_dpm *dpm, int arch_mode); int arm_dpm_initialize(struct arm_dpm *dpm); int arm_dpm_read_current_registers(struct arm_dpm *); +int arm_dpm_read_current_registers_64(struct arm_dpm *); int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); -- ------------------------------------------------------------------------------ New Year. New Location. New Benefits. New Data Center in Ashburn, VA. GigeNET is offering a free month of service with a new server in Ashburn. Choose from 2 high performing configs, both with 100TB of bandwidth. Higher redundancy.Lower latency.Increased capacity.Completely compliant. http://p.sf.net/sfu/gigenet _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel