target/riscv: try all triggers when setting itrigger/etrigger/icount breakpoints

different triggers may have different capabilities so we'd better to
try them all

Signed-off-by: Parshintsev Anatoly <anatoly.parshintsev@syntacore.com>
This commit is contained in:
Parshintsev Anatoly 2024-09-02 20:27:17 +03:00
parent 909bbb899b
commit c0f689d1a4
1 changed files with 81 additions and 53 deletions

View File

@ -619,8 +619,9 @@ static int find_first_trigger_by_id(struct target *target, int unique_id)
return -1;
}
static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2,
riscv_reg_t tdata1_ignore_mask)
static int stdtrig_set_tx_impl(struct target *target, unsigned int idx,
riscv_reg_t tdata1, riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask,
bool update_tdata2)
{
riscv_reg_t tdata1_rb, tdata2_rb;
// Select which trigger to use
@ -631,21 +632,23 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat
if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
return ERROR_FAIL;
// Set trigger data for tdata2 (and tdata3 if it was supported)
if (riscv_reg_set(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
// Set trigger data for tdata2 (tdata3 - not implemented) if it was supported
if (update_tdata2 &&
riscv_reg_set(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
return ERROR_FAIL;
// Set trigger data for tdata1
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
return ERROR_FAIL;
// Read back tdata1, tdata2, (tdata3), and check if the configuration is supported
// Read back tdata1, tdata2, (tdata3 - not implemented), and check if the configuration is supported
if (riscv_reg_get(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
if (riscv_reg_get(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
if (update_tdata2 &&
riscv_reg_get(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
return ERROR_FAIL;
bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask);
bool tdata2_config_denied = tdata2 != tdata2_rb;
bool tdata2_config_denied = update_tdata2 && tdata2 != tdata2_rb;
if (tdata1_config_denied || tdata2_config_denied) {
LOG_TARGET_DEBUG(target, "Trigger %u doesn't support what we need.", idx);
@ -666,6 +669,20 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat
return ERROR_OK;
}
static int sdtrig_set_t1(struct target *target, unsigned int idx,
riscv_reg_t tdata1, riscv_reg_t tdata1_ignore_mask)
{
return stdtrig_set_tx_impl(target, idx, tdata1, /* tdata2 */ 0,
tdata1_ignore_mask, /* update tdata2 */ false);
}
static int sdtrig_set_t1t2(struct target *target, unsigned int idx,
riscv_reg_t tdata1, riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask)
{
return stdtrig_set_tx_impl(target, idx, tdata1, tdata2, tdata1_ignore_mask,
/* update tdata2 */ true);
}
static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
{
int ret;
@ -684,7 +701,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
const uint32_t bpcontrol_bpaction = 0xff << 11;
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx);
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_LEGACY, /* chained */ false, &idx);
if (ret != ERROR_OK)
return ret;
@ -706,7 +723,8 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
ret = sdtrig_set_t1t2(target, idx, tdata1, tdata2,
/* tdata1 ignore mask */ 0);
if (ret != ERROR_OK)
return ret;
r->trigger_unique_id[idx] = trigger->unique_id;
@ -810,7 +828,7 @@ static int try_use_trigger_and_cache_result(struct target *target, unsigned int
if (wp_triggers_cache_search(target, idx, tdata1, tdata2))
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
int ret = set_trigger(target, idx, tdata1, tdata2, tdata1_ignore_mask);
int ret = sdtrig_set_t1t2(target, idx, tdata1, tdata2, tdata1_ignore_mask);
/* Add these values to the cache to remember that they are not supported. */
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
@ -860,7 +878,7 @@ static int try_setup_chained_match_triggers(struct target *target,
/* Find the first 2 consecutive triggers, supporting required tdata1 values */
for (unsigned int idx = 0;
find_next_free_trigger(target, trigger_type, true, &idx) == ERROR_OK;
find_next_free_trigger(target, trigger_type, /* chained */ true, &idx) == ERROR_OK;
++idx) {
ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2,
t1.tdata1_ignore_mask);
@ -879,7 +897,10 @@ static int try_setup_chained_match_triggers(struct target *target,
return ERROR_OK;
}
/* Undo the setting of the previous trigger */
int ret_undo = set_trigger(target, idx, 0, 0, 0);
// BUG: fixme. once tdata1 is written with zero
// we should not readback tdata1
int ret_undo = sdtrig_set_t1t2(target, idx,
/* tdata1 */ 0, /* tdata2 */0, /* tdata1_mask */ 0);
if (ret_undo != ERROR_OK)
return ret_undo;
@ -1116,12 +1137,9 @@ static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu,
bool m, bool s, bool u, bool pending, unsigned int count,
int unique_id)
{
int ret;
riscv_reg_t tdata1;
RISCV_INFO(r);
tdata1 = 0;
riscv_reg_t tdata1 = 0;
tdata1 = set_field(tdata1, CSR_ICOUNT_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ICOUNT);
tdata1 = set_field(tdata1, CSR_ICOUNT_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_ICOUNT_ACTION, CSR_ICOUNT_ACTION_DEBUG_MODE);
@ -1133,27 +1151,30 @@ static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu,
tdata1 = set_field(tdata1, CSR_ICOUNT_U, u);
tdata1 = set_field(tdata1, CSR_ICOUNT_COUNT, count);
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ICOUNT, false, &idx);
if (ret != ERROR_OK)
return ret;
ret = set_trigger(target, idx, tdata1, 0, 0);
if (ret != ERROR_OK)
return ret;
int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
for (unsigned int idx = 0;
find_next_free_trigger(target, CSR_TDATA1_TYPE_ICOUNT,
/* chained */ false, &idx) == ERROR_OK;
++idx) {
ret = sdtrig_set_t1(target, idx, tdata1, /* tdata1 ignore mask */ 0);
if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = unique_id;
return ERROR_OK;
}
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
break;
}
return ret;
}
static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu,
bool nmi, bool m, bool s, bool u, riscv_reg_t interrupts,
int unique_id)
{
int ret;
riscv_reg_t tdata1, tdata2;
RISCV_INFO(r);
tdata1 = 0;
riscv_reg_t tdata1 = 0;
tdata1 = set_field(tdata1, CSR_ITRIGGER_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ITRIGGER);
tdata1 = set_field(tdata1, CSR_ITRIGGER_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_ITRIGGER_ACTION, CSR_ITRIGGER_ACTION_DEBUG_MODE);
@ -1164,29 +1185,31 @@ static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu,
tdata1 = set_field(tdata1, CSR_ITRIGGER_S, s);
tdata1 = set_field(tdata1, CSR_ITRIGGER_U, u);
tdata2 = interrupts;
riscv_reg_t tdata2 = interrupts;
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx);
if (ret != ERROR_OK)
return ret;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
if (ret != ERROR_OK)
return ret;
int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
for (unsigned int idx = 0;
find_next_free_trigger(target, CSR_TDATA1_TYPE_ITRIGGER,
/* chained */ false, &idx) == ERROR_OK;
++idx) {
ret = sdtrig_set_t1t2(target, idx, tdata1, tdata2, /* tdata1 ignore mask */ 0);
if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = unique_id;
return ERROR_OK;
}
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
break;
}
return ret;
}
static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu,
bool m, bool s, bool u, riscv_reg_t exception_codes,
int unique_id)
{
int ret;
riscv_reg_t tdata1, tdata2;
RISCV_INFO(r);
tdata1 = 0;
riscv_reg_t tdata1 = 0;
tdata1 = set_field(tdata1, CSR_ETRIGGER_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ETRIGGER);
tdata1 = set_field(tdata1, CSR_ETRIGGER_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_ETRIGGER_ACTION, CSR_ETRIGGER_ACTION_DEBUG_MODE);
@ -1196,18 +1219,23 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu,
tdata1 = set_field(tdata1, CSR_ETRIGGER_S, s);
tdata1 = set_field(tdata1, CSR_ETRIGGER_U, u);
tdata2 = exception_codes;
riscv_reg_t tdata2 = exception_codes;
unsigned int idx = 0;
ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx);
if (ret != ERROR_OK)
return ret;
ret = set_trigger(target, idx, tdata1, tdata2, 0);
if (ret != ERROR_OK)
return ret;
int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
for (unsigned int idx = 0;
find_next_free_trigger(target, CSR_TDATA1_TYPE_ETRIGGER,
/* chained */ false, &idx) == ERROR_OK;
++idx) {
ret = sdtrig_set_t1t2(target, idx, tdata1, tdata2, /* tdata1 ignore mask */ 0);
if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = unique_id;
return ERROR_OK;
}
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
break;
}
return ret;
}
static int add_trigger(struct target *target, struct trigger *trigger)
{