Clear dmode triggers when we first halt the target

This helps repeated runs of the testsuite pass, and is probably a good
idea in general.

Change-Id: I89ed167968f8b8817c66f1718f374d0c502780c7
This commit is contained in:
Tim Newsome 2016-09-29 10:23:46 -07:00
parent 78fe0b56db
commit 4dbc9962d3
1 changed files with 42 additions and 19 deletions

View File

@ -170,6 +170,8 @@ typedef struct {
// unique_id of the breakpoint/watchpoint that is using it.
int trigger_unique_id[MAX_HWBPS];
unsigned int trigger_count;
// Number of run-test/idle cycles the target requests we do after each dbus
// access.
unsigned int dtmcontrol_idle;
@ -189,6 +191,7 @@ typedef struct {
uint64_t gpr_cache[32];
bool need_strict_step;
bool never_halted;
} riscv_info_t;
typedef struct {
@ -1017,12 +1020,14 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
return ERROR_FAIL;
}
*value = cache_get(target, SLOT0);
LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value);
return ERROR_OK;
}
static int write_csr(struct target *target, uint32_t csr, uint64_t value)
{
LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value);
cache_set_load(target, 0, S0, SLOT0);
cache_set32(target, 1, csrw(S0, csr));
cache_set_jump(target, 2);
@ -1404,23 +1409,13 @@ static int add_trigger(struct target *target, struct trigger *trigger)
maybe_read_tselect(target);
int i;
for (i = 0; i < MAX_HWBPS; i++) {
unsigned int i;
for (i = 0; i < info->trigger_count; i++) {
if (info->trigger_unique_id[i] != -1) {
continue;
}
uint64_t tselect = i;
write_csr(target, CSR_TSELECT, tselect);
uint64_t tselect_rb;
read_csr(target, &tselect_rb, CSR_TSELECT);
if (tselect_rb != tselect) {
// We've run out of breakpoints.
LOG_ERROR("Couldn't find an available hardware trigger. "
"(0x%" PRIx64 " != 0x%" PRIx64 ")", tselect,
tselect_rb);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
write_csr(target, CSR_TSELECT, i);
uint64_t tdata1;
read_csr(target, &tdata1, CSR_TDATA1);
@ -1476,7 +1471,7 @@ static int add_trigger(struct target *target, struct trigger *trigger)
info->trigger_unique_id[i] = trigger->unique_id;
break;
}
if (i >= MAX_HWBPS) {
if (i >= info->trigger_count) {
LOG_ERROR("Couldn't find an available hardware trigger.");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
@ -1490,13 +1485,13 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
maybe_read_tselect(target);
int i;
for (i = 0; i < MAX_HWBPS; i++) {
unsigned int i;
for (i = 0; i < info->trigger_count; i++) {
if (info->trigger_unique_id[i] == trigger->unique_id) {
break;
}
}
if (i >= MAX_HWBPS) {
if (i >= info->trigger_count) {
LOG_ERROR("Couldn't find the hardware resources used by hardware "
"trigger.");
return ERROR_FAIL;
@ -1800,13 +1795,15 @@ static int riscv_examine(struct target *target)
// Update register list to match discovered XLEN.
update_reg_list(target);
target_set_examined(target);
if (read_csr(target, &info->misa, CSR_MISA) != ERROR_OK) {
LOG_ERROR("Failed to read misa.");
return ERROR_FAIL;
}
info->never_halted = true;
target_set_examined(target);
return ERROR_OK;
}
@ -2001,6 +1998,32 @@ static int handle_halt(struct target *target, bool announce)
cause, info->dcsr);
}
if (info->never_halted) {
info->never_halted = false;
// Disable any hardware triggers that have dmode set. We can't have set
// them ourselves. Maybe they're left over from some killed debug
// session.
// Count the number of triggers while we're at it.
int result = maybe_read_tselect(target);
if (result != ERROR_OK)
return result;
for (info->trigger_count = 0; info->trigger_count < MAX_HWBPS; info->trigger_count++) {
write_csr(target, CSR_TSELECT, info->trigger_count);
uint64_t tselect_rb;
read_csr(target, &tselect_rb, CSR_TSELECT);
if (info->trigger_count != tselect_rb)
break;
uint64_t tdata1;
read_csr(target, &tdata1, CSR_TDATA1);
if ((tdata1 & MCONTROL_DMODE(info->xlen)) &&
(tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD))) {
write_csr(target, CSR_TDATA1, 0);
}
}
}
if (announce) {
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}