Implement watchpoints on Cortex-A
This commit is contained in:
parent
1aadcf2678
commit
b5ef9e5bcf
|
@ -73,6 +73,8 @@ struct cortexa_priv {
|
|||
uint16_t hw_breakpoint_mask;
|
||||
uint32_t bcr0;
|
||||
uint32_t bvr0;
|
||||
unsigned hw_watchpoint_max;
|
||||
uint16_t hw_watchpoint_mask;
|
||||
bool mmu_fault;
|
||||
};
|
||||
|
||||
|
@ -116,6 +118,17 @@ struct cortexa_priv {
|
|||
#define DBGBCR_BAS_HIGH_HW (0xc << 5)
|
||||
#define DBGBCR_EN (1 << 0)
|
||||
|
||||
#define DBGWVR(i) (96+(i))
|
||||
#define DBGWCR(i) (112+(i))
|
||||
#define DBGWCR_LSC_LOAD (0b01 << 3)
|
||||
#define DBGWCR_LSC_STORE (0b10 << 3)
|
||||
#define DBGWCR_LSC_ANY (0b11 << 3)
|
||||
#define DBGWCR_BAS_BYTE (0b0001 << 5)
|
||||
#define DBGWCR_BAS_HALFWORD (0b0011 << 5)
|
||||
#define DBGWCR_BAS_WORD (0b1111 << 5)
|
||||
#define DBGWCR_PAC_ANY (0b11 << 1)
|
||||
#define DBGWCR_EN (1 << 0)
|
||||
|
||||
/* Instruction encodings for accessing the coprocessor interface */
|
||||
#define MCR 0xee000010
|
||||
#define MRC 0xee100010
|
||||
|
@ -349,6 +362,7 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base)
|
|||
adiv5_ap_write(apb, ADIV5_AP_CSW, csw);
|
||||
uint32_t dbgdidr = apb_read(t, DBGDIDR);
|
||||
priv->hw_breakpoint_max = ((dbgdidr >> 24) & 15)+1;
|
||||
priv->hw_watchpoint_max = ((dbgdidr >> 28) & 15)+1;
|
||||
|
||||
t->check_error = cortexa_check_error;
|
||||
|
||||
|
@ -752,6 +766,49 @@ static int cortexa_breakwatch_set(target *t, struct breakwatch *bw)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case TARGET_WATCH_WRITE:
|
||||
case TARGET_WATCH_READ:
|
||||
case TARGET_WATCH_ACCESS:
|
||||
for (i = 0; i < priv->hw_watchpoint_max; i++)
|
||||
if ((priv->hw_watchpoint_mask & (1 << i)) == 0)
|
||||
break;
|
||||
|
||||
if (i == priv->hw_watchpoint_max)
|
||||
return -1;
|
||||
|
||||
bw->reserved[0] = i;
|
||||
priv->hw_watchpoint_mask |= (1 << i);
|
||||
|
||||
{
|
||||
uint32_t wcr = DBGWCR_PAC_ANY | DBGWCR_EN;
|
||||
uint32_t bas = 0;
|
||||
switch(bw->size) { /* Convert bytes size to BAS bits */
|
||||
case 1: bas = DBGWCR_BAS_BYTE; break;
|
||||
case 2: bas = DBGWCR_BAS_HALFWORD; break;
|
||||
case 4: bas = DBGWCR_BAS_WORD; break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
/* Apply shift based on address LSBs */
|
||||
wcr |= bas << (bw->addr & 3);
|
||||
|
||||
switch (bw->type) { /* Convert gdb type */
|
||||
case TARGET_WATCH_WRITE: wcr |= DBGWCR_LSC_STORE; break;
|
||||
case TARGET_WATCH_READ: wcr |= DBGWCR_LSC_LOAD; break;
|
||||
case TARGET_WATCH_ACCESS: wcr |= DBGWCR_LSC_ANY; break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
apb_write(t, DBGWCR(i), wcr);
|
||||
apb_write(t, DBGWVR(i), bw->addr & ~3);
|
||||
DEBUG("Watchpoint set WCR = 0x%08x, WVR = %08x\n",
|
||||
apb_read(t, DBGWCR(i)),
|
||||
apb_read(t, DBGWVR(i)));
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
@ -779,6 +836,12 @@ static int cortexa_breakwatch_clear(target *t, struct breakwatch *bw)
|
|||
if (i == 0)
|
||||
priv->bcr0 = 0;
|
||||
return 0;
|
||||
case TARGET_WATCH_WRITE:
|
||||
case TARGET_WATCH_READ:
|
||||
case TARGET_WATCH_ACCESS:
|
||||
priv->hw_watchpoint_mask &= ~(1 << i);
|
||||
apb_write(t, DBGWCR(i), 0);
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue