arm_dpm: Add 64bit register handling.
Add various function to read/write ARMv8 registers. Change-Id: I16f2829bdd0e87b050a51e414ff675d5c21bcbae Signed-off-by: David Ung <david.ung.42@gmail.com> Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com>
This commit is contained in:
parent
9cbfc9feb3
commit
84a0bb4a3c
|
@ -130,11 +130,11 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
|
||||||
return retval;
|
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;
|
uint32_t value;
|
||||||
int retval;
|
int retval = ERROR_FAIL;
|
||||||
|
|
||||||
switch (regnum) {
|
switch (regnum) {
|
||||||
case 0 ... 14:
|
case 0 ... 14:
|
||||||
|
@ -190,10 +190,57 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* just write the register -- rely on the core mode being right */
|
static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
|
||||||
{
|
{
|
||||||
int retval;
|
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)
|
||||||
|
{
|
||||||
|
int retval = ERROR_FAIL;
|
||||||
uint32_t value = buf_get_u32(r->value, 0, 32);
|
uint32_t value = buf_get_u32(r->value, 0, 32);
|
||||||
|
|
||||||
switch (regnum) {
|
switch (regnum) {
|
||||||
|
@ -243,19 +290,46 @@ 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);
|
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)
|
||||||
* 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).
|
int retval = ERROR_FAIL;
|
||||||
* In normal operation this is called on entry to halting debug state,
|
uint32_t i;
|
||||||
* possibly after some other operations supporting restore of debug state
|
uint64_t value = buf_get_u64(r->value, 0, 64);
|
||||||
* or making sure the CPU is fully idle (drain write buffer, etc).
|
|
||||||
*/
|
switch (regnum) {
|
||||||
int arm_dpm_read_current_registers(struct arm_dpm *dpm)
|
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)
|
||||||
{
|
{
|
||||||
struct arm *arm = dpm->arm;
|
struct arm *arm = dpm->arm;
|
||||||
uint32_t cpsr;
|
uint32_t cpsr, instr, core_regs;
|
||||||
int retval;
|
int retval;
|
||||||
struct reg *r;
|
struct reg *r;
|
||||||
|
enum arm_state core_state = arm->core_state;
|
||||||
|
|
||||||
retval = dpm->prepare(dpm);
|
retval = dpm->prepare(dpm);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -270,16 +344,22 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
|
||||||
}
|
}
|
||||||
r->dirty = true;
|
r->dirty = true;
|
||||||
|
|
||||||
retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
|
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);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* update core mode and state, plus shadow mapping for R8..R14 */
|
/* update core mode and state, plus shadow mapping for R8..R14 */
|
||||||
arm_set_cpsr(arm, cpsr);
|
arm_set_cpsr(arm, cpsr);
|
||||||
|
|
||||||
|
core_regs = arm->core_cache->num_regs;
|
||||||
|
|
||||||
/* REVISIT we can probably avoid reading R1..R14, saving time... */
|
/* REVISIT we can probably avoid reading R1..R14, saving time... */
|
||||||
for (unsigned i = 1; i < 16; i++) {
|
for (unsigned i = 1; i < core_regs; i++) {
|
||||||
r = arm_reg_current(arm, i);
|
r = dpm->arm_reg_current(arm, i);
|
||||||
if (r->valid)
|
if (r->valid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -300,6 +380,23 @@ fail:
|
||||||
return retval;
|
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
|
/* Avoid needless I/O ... leave breakpoints and watchpoints alone
|
||||||
* unless they're removed, or need updating because of single-stepping
|
* unless they're removed, or need updating because of single-stepping
|
||||||
* or running debugger code.
|
* or running debugger code.
|
||||||
|
@ -348,6 +445,160 @@ done:
|
||||||
|
|
||||||
static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
|
static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
|
||||||
|
|
||||||
|
|
||||||
|
static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
|
||||||
|
{
|
||||||
|
struct arm *arm = dpm->arm;
|
||||||
|
struct reg_cache *cache = arm->core_cache;
|
||||||
|
int retval;
|
||||||
|
bool did_write;
|
||||||
|
|
||||||
|
/* 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...
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
enum arm_mode mode = ARM_MODE_ANY;
|
||||||
|
|
||||||
|
did_write = false;
|
||||||
|
|
||||||
|
/* check everything except our scratch register R0 */
|
||||||
|
for (unsigned i = 1; i < cache->num_regs; i++) {
|
||||||
|
struct arm_reg *r;
|
||||||
|
unsigned regnum;
|
||||||
|
|
||||||
|
/* also skip PC, CPSR, and non-dirty */
|
||||||
|
if (i == 15)
|
||||||
|
continue;
|
||||||
|
if (arm->cpsr == cache->reg_list + i)
|
||||||
|
continue;
|
||||||
|
if (!cache->reg_list[i].dirty)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = cache->reg_list[i].arch_info;
|
||||||
|
regnum = r->num;
|
||||||
|
|
||||||
|
/* may need to pick and set a mode */
|
||||||
|
if (!did_write) {
|
||||||
|
enum arm_mode tmode;
|
||||||
|
|
||||||
|
did_write = true;
|
||||||
|
mode = tmode = r->mode;
|
||||||
|
|
||||||
|
/* cope with special cases */
|
||||||
|
switch (regnum) {
|
||||||
|
case 8 ... 12:
|
||||||
|
/* r8..r12 "anything but FIQ" case;
|
||||||
|
* we "know" core mode is accurate
|
||||||
|
* since we haven't changed it yet
|
||||||
|
*/
|
||||||
|
if (arm->core_mode == ARM_MODE_FIQ
|
||||||
|
&& ARM_MODE_ANY
|
||||||
|
!= mode)
|
||||||
|
tmode = ARM_MODE_USR;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
/* SPSR */
|
||||||
|
regnum++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* REVISIT error checks */
|
||||||
|
if (tmode != ARM_MODE_ANY) {
|
||||||
|
retval = dpm_modeswitch(dpm, tmode);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r->mode != mode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
retval = dpm_write_reg(dpm,
|
||||||
|
&cache->reg_list[i],
|
||||||
|
regnum);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (did_write);
|
||||||
|
|
||||||
|
/* Restore original CPSR ... assuming either that we changed it,
|
||||||
|
* or it's dirty. Must write PC to ensure the return address is
|
||||||
|
* defined, and must not write it before CPSR.
|
||||||
|
*/
|
||||||
|
retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
arm->cpsr->dirty = false;
|
||||||
|
|
||||||
|
/* restore the PC, make sure to also switch the core state
|
||||||
|
* to whatever it was set to with "arm core_state" command.
|
||||||
|
* target code will have set PC to an appropriate resume address.
|
||||||
|
*/
|
||||||
|
retval = dpm_write_pc_core_state(dpm, arm->pc);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
/* on Cortex-A5 (as found on NXP VF610 SoC), BX instruction
|
||||||
|
* executed in debug state doesn't appear to set the PC,
|
||||||
|
* explicitly set it with a "MOV pc, r0". This doesn't influence
|
||||||
|
* CPSR on Cortex-A9 so it should be OK. Maybe due to different
|
||||||
|
* debug version?
|
||||||
|
*/
|
||||||
|
retval = dpm_write_reg(dpm, arm->pc, 15);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
arm->pc->dirty = false;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* Writes all modified core registers for all processor modes. In normal
|
||||||
* operation this is called on exit from halting debug state.
|
* operation this is called on exit from halting debug state.
|
||||||
|
@ -361,7 +612,6 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
|
||||||
struct arm *arm = dpm->arm;
|
struct arm *arm = dpm->arm;
|
||||||
struct reg_cache *cache = arm->core_cache;
|
struct reg_cache *cache = arm->core_cache;
|
||||||
int retval;
|
int retval;
|
||||||
bool did_write;
|
|
||||||
|
|
||||||
retval = dpm->prepare(dpm);
|
retval = dpm->prepare(dpm);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -401,108 +651,10 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
|
||||||
* be queued, and need (efficient/batched) flushing later.
|
* be queued, and need (efficient/batched) flushing later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Scan the registers until we find one that's both dirty and
|
if (cache->reg_list[0].size == 64)
|
||||||
* eligible for flushing. Flush that and everything else that
|
retval = arm_dpm_write_dirty_registers_64(dpm);
|
||||||
* shares the same core mode setting. Typically this won't
|
else
|
||||||
* actually find anything to do...
|
retval = arm_dpm_write_dirty_registers_32(dpm);
|
||||||
*/
|
|
||||||
do {
|
|
||||||
enum arm_mode mode = ARM_MODE_ANY;
|
|
||||||
|
|
||||||
did_write = false;
|
|
||||||
|
|
||||||
/* check everything except our scratch register R0 */
|
|
||||||
for (unsigned i = 1; i < cache->num_regs; i++) {
|
|
||||||
struct arm_reg *r;
|
|
||||||
unsigned regnum;
|
|
||||||
|
|
||||||
/* also skip PC, CPSR, and non-dirty */
|
|
||||||
if (i == 15)
|
|
||||||
continue;
|
|
||||||
if (arm->cpsr == cache->reg_list + i)
|
|
||||||
continue;
|
|
||||||
if (!cache->reg_list[i].dirty)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = cache->reg_list[i].arch_info;
|
|
||||||
regnum = r->num;
|
|
||||||
|
|
||||||
/* may need to pick and set a mode */
|
|
||||||
if (!did_write) {
|
|
||||||
enum arm_mode tmode;
|
|
||||||
|
|
||||||
did_write = true;
|
|
||||||
mode = tmode = r->mode;
|
|
||||||
|
|
||||||
/* cope with special cases */
|
|
||||||
switch (regnum) {
|
|
||||||
case 8 ... 12:
|
|
||||||
/* r8..r12 "anything but FIQ" case;
|
|
||||||
* we "know" core mode is accurate
|
|
||||||
* since we haven't changed it yet
|
|
||||||
*/
|
|
||||||
if (arm->core_mode == ARM_MODE_FIQ
|
|
||||||
&& ARM_MODE_ANY
|
|
||||||
!= mode)
|
|
||||||
tmode = ARM_MODE_USR;
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
/* SPSR */
|
|
||||||
regnum++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* REVISIT error checks */
|
|
||||||
if (tmode != ARM_MODE_ANY) {
|
|
||||||
retval = dpm_modeswitch(dpm, tmode);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r->mode != mode)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
retval = dpm_write_reg(dpm,
|
|
||||||
&cache->reg_list[i],
|
|
||||||
regnum);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (did_write);
|
|
||||||
|
|
||||||
/* Restore original CPSR ... assuming either that we changed it,
|
|
||||||
* or it's dirty. Must write PC to ensure the return address is
|
|
||||||
* defined, and must not write it before CPSR.
|
|
||||||
*/
|
|
||||||
retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
arm->cpsr->dirty = false;
|
|
||||||
|
|
||||||
/* restore the PC, make sure to also switch the core state
|
|
||||||
* to whatever it was set to with "arm core_state" command.
|
|
||||||
* target code will have set PC to an appropriate resume address.
|
|
||||||
*/
|
|
||||||
retval = dpm_write_pc_core_state(dpm, arm->pc);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
/* on Cortex-A5 (as found on NXP VF610 SoC), BX instruction
|
|
||||||
* executed in debug state doesn't appear to set the PC,
|
|
||||||
* explicitly set it with a "MOV pc, r0". This doesn't influence
|
|
||||||
* CPSR on Cortex-A9 so it should be OK. Maybe due to different
|
|
||||||
* debug version?
|
|
||||||
*/
|
|
||||||
retval = dpm_write_reg(dpm, arm->pc, 15);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
arm->pc->dirty = false;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* (void) */ dpm->finish(dpm);
|
/* (void) */ dpm->finish(dpm);
|
||||||
done:
|
done:
|
||||||
|
@ -973,8 +1125,8 @@ int arm_dpm_setup(struct arm_dpm *dpm)
|
||||||
|
|
||||||
/* register access setup */
|
/* register access setup */
|
||||||
arm->full_context = arm_dpm_full_context;
|
arm->full_context = arm_dpm_full_context;
|
||||||
arm->read_core_reg = arm_dpm_read_core_reg;
|
arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg;
|
||||||
arm->write_core_reg = arm_dpm_write_core_reg;
|
arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg;
|
||||||
|
|
||||||
/* avoid duplicating the register cache */
|
/* avoid duplicating the register cache */
|
||||||
if (arm->core_cache == NULL) {
|
if (arm->core_cache == NULL) {
|
||||||
|
@ -999,12 +1151,21 @@ int arm_dpm_setup(struct arm_dpm *dpm)
|
||||||
target->type->add_watchpoint = dpm_add_watchpoint;
|
target->type->add_watchpoint = dpm_add_watchpoint;
|
||||||
target->type->remove_watchpoint = dpm_remove_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 */
|
/* FIXME add vector catch support */
|
||||||
|
|
||||||
dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
|
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||||
dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
|
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);
|
dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
|
||||||
|
|
||||||
if (!dpm->dbp || !dpm->dwp) {
|
if (!dpm->dbp || !dpm->dwp) {
|
||||||
|
|
|
@ -86,10 +86,19 @@ struct arm_dpm {
|
||||||
int (*instr_read_data_dcc)(struct arm_dpm *,
|
int (*instr_read_data_dcc)(struct arm_dpm *,
|
||||||
uint32_t opcode, uint32_t *data);
|
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. */
|
/** Runs one instruction, reading data from r0 after execution. */
|
||||||
int (*instr_read_data_r0)(struct arm_dpm *,
|
int (*instr_read_data_r0)(struct arm_dpm *,
|
||||||
uint32_t opcode, uint32_t *data);
|
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 */
|
/* BREAKPOINT/WATCHPOINT SUPPORT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,6 +140,7 @@ int arm_dpm_setup(struct arm_dpm *dpm);
|
||||||
int arm_dpm_initialize(struct arm_dpm *dpm);
|
int arm_dpm_initialize(struct arm_dpm *dpm);
|
||||||
|
|
||||||
int arm_dpm_read_current_registers(struct arm_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);
|
int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue