From c0f689d1a4cb877306f241a3f53d041d2a1eb632 Mon Sep 17 00:00:00 2001 From: Parshintsev Anatoly Date: Mon, 2 Sep 2024 20:27:17 +0300 Subject: [PATCH] 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 --- src/target/riscv/riscv.c | 134 +++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 53 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index f52ee00d2..512f27bd4 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -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; - r->trigger_unique_id[idx] = unique_id; - return ERROR_OK; + 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; - r->trigger_unique_id[idx] = unique_id; - return ERROR_OK; + 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,17 +1219,22 @@ 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; - r->trigger_unique_id[idx] = unique_id; - return ERROR_OK; + 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)