From 2258a59a0f1baa376972818b35530e50645f7c8f Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 27 Dec 2022 12:53:52 -0800 Subject: [PATCH 1/5] target/riscv: Use macros for trigger types. Change-Id: I6ced3fb5a22bff4694fbceb8cf91f6cf6ce37ebf Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 9e46cda42..5a59d5aac 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1071,13 +1071,13 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) uint64_t hit_mask = 0; switch (type) { - case 1: + case CSR_TDATA1_TYPE_LEGACY: /* Doesn't support hit bit. */ break; - case 2: + case CSR_TDATA1_TYPE_MCONTROL: hit_mask = CSR_MCONTROL_HIT; break; - case 6: + case CSR_TDATA1_TYPE_MCONTROL6: hit_mask = CSR_MCONTROL6_HIT; break; default: @@ -4120,16 +4120,16 @@ int riscv_enumerate_triggers(struct target *target) if (type == 0) break; switch (type) { - case 1: + case CSR_TDATA1_TYPE_LEGACY: /* On these older cores we don't support software using * triggers. */ riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; - case 2: + case CSR_TDATA1_TYPE_MCONTROL: if (tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; - case 6: + case CSR_TDATA1_TYPE_MCONTROL6: if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; From 0b022a349e41a054bfda66b975769bbfa5e60c0b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 18 Nov 2022 15:57:17 -0800 Subject: [PATCH 2/5] target/riscv: Add `riscv itrigger` command. This lets the user set an itrigger trigger, which doesn't fit in the normal breakpoint abstraction. This implementation only allows control of a single itrigger. Hardware could support more than one, and that may be useful to catch different interrupts in different execution modes. But it would make the code/UI more complex and it feels like an unlikely use case. Change-Id: I76c88636ee73d4bd298b2bd1435cb5d052e86c91 Signed-off-by: Tim Newsome --- doc/openocd.texi | 22 ++++++ src/target/riscv/riscv.c | 142 +++++++++++++++++++++++++++++++++++++-- src/target/riscv/riscv.h | 6 +- 3 files changed, 163 insertions(+), 7 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index e671b80b5..b5a16a961 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10716,6 +10716,28 @@ Perform a 32-bit DMI read at address, returning the value. Perform a 32-bit DMI write of value at address. @end deffn +@subsection RISC-V Trigger Commands + +The RISC-V Debug Specification defines several trigger types that don't map +cleanly onto OpenOCD's notion of hardware breakpoints. These commands let you +set those triggers directly. (It's also possible to do so by writing the +appropriate CSRs.) + +@deffn {Command} {riscv itrigger set} [@option{m}] [@option{s}] [@option{u}] [@option{vs}] [@option{vu}] [@option{nmi}] mie_bits +Set an interrupt trigger (type 4) on the current target, which halts the target when it +fires. @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control +which execution modes the trigger fires in. If [@option{nmi}] is passed then +the trigger will fire on non-maskable interrupts in those modes. @var{mie_bits} +controls which interrupts the trigger fires on, using the same bit assignments +as in the mie CSR (defined in the RISC-V Privileged Spec). + +For details on this trigger type, see the RISC-V Debug Specification. +@end deffn + +@deffn {Command} {riscv itrigger clear} +Clear the type 4 trigger that was set using @command{riscv itrigger set}. +@end deffn + @section ARC Architecture @cindex ARC diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 5a59d5aac..6cd3a0198 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -506,6 +506,17 @@ static int find_trigger(struct target *target, int type, bool chained, int *idx) return ERROR_FAIL; } +static int find_first_trigger_by_id(struct target *target, int unique_id) +{ + RISCV_INFO(r); + + for (unsigned i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == unique_id) + return i; + } + return -1; +} + static int set_trigger(struct target *target, int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask) { @@ -661,6 +672,38 @@ MATCH_EQUAL: return ERROR_OK; } +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 idx, ret; + riscv_reg_t tdata1, tdata2; + + RISCV_INFO(r); + + 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); + tdata1 = set_field(tdata1, CSR_ITRIGGER_VS, vs); + tdata1 = set_field(tdata1, CSR_ITRIGGER_VU, vu); + tdata1 = set_field(tdata1, CSR_ITRIGGER_NMI, nmi); + tdata1 = set_field(tdata1, CSR_ITRIGGER_M, m); + tdata1 = set_field(tdata1, CSR_ITRIGGER_S, s); + tdata1 = set_field(tdata1, CSR_ITRIGGER_U, u); + + tdata2 = interrupts; + + ret = find_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; +} + static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger) { int idx, ret; @@ -937,7 +980,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_OK; } -static int remove_trigger(struct target *target, struct trigger *trigger) +static int remove_trigger(struct target *target, int unique_id) { RISCV_INFO(r); @@ -951,12 +994,12 @@ static int remove_trigger(struct target *target, struct trigger *trigger) bool done = false; for (unsigned int i = 0; i < r->trigger_count; i++) { - if (r->trigger_unique_id[i] == trigger->unique_id) { + if (r->trigger_unique_id[i] == unique_id) { riscv_set_register(target, GDB_REGNO_TSELECT, i); riscv_set_register(target, GDB_REGNO_TDATA1, 0); r->trigger_unique_id[i] = -1; LOG_TARGET_DEBUG(target, "Stop using resource %d for bp %d", - i, trigger->unique_id); + i, unique_id); done = true; } } @@ -986,7 +1029,7 @@ int riscv_remove_breakpoint(struct target *target, } else if (breakpoint->type == BKPT_HARD) { struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); - int result = remove_trigger(target, &trigger); + int result = remove_trigger(target, trigger.unique_id); if (result != ERROR_OK) return result; @@ -1035,7 +1078,7 @@ int riscv_remove_watchpoint(struct target *target, struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); - int result = remove_trigger(target, &trigger); + int result = remove_trigger(target, trigger.unique_id); if (result != ERROR_OK) return result; watchpoint->is_set = false; @@ -1080,6 +1123,9 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) case CSR_TDATA1_TYPE_MCONTROL6: hit_mask = CSR_MCONTROL6_HIT; break; + case CSR_TDATA1_TYPE_ITRIGGER: + hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target)); + break; default: LOG_DEBUG("trigger %d has unknown type %d", i, type); continue; @@ -3173,6 +3219,81 @@ COMMAND_HANDLER(riscv_set_ebreaku) return ERROR_OK; } +COMMAND_HANDLER(riscv_itrigger) +{ + if (CMD_ARGC < 1) { + LOG_ERROR("Command takes at least 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + const int ITRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ITRIGGER; + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (!strcmp(CMD_ARGV[0], "set")) { + if (find_first_trigger_by_id(target, ITRIGGER_UNIQUE_ID) >= 0) { + LOG_TARGET_ERROR(target, "An itrigger is already set, and OpenOCD " + "doesn't support setting more than one at a time."); + return ERROR_FAIL; + } + bool vs = false; + bool vu = false; + bool nmi = false; + bool m = false; + bool s = false; + bool u = false; + riscv_reg_t interrupts = 0; + + for (unsigned int i = 1; i < CMD_ARGC; i++) { + if (!strcmp(CMD_ARGV[i], "vs")) + vs = true; + else if (!strcmp(CMD_ARGV[i], "vu")) + vu = true; + else if (!strcmp(CMD_ARGV[i], "nmi")) + nmi = true; + else if (!strcmp(CMD_ARGV[i], "m")) + m = true; + else if (!strcmp(CMD_ARGV[i], "s")) + s = true; + else if (!strcmp(CMD_ARGV[i], "u")) + u = true; + else + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], interrupts); + } + if (!nmi && interrupts == 0) { + LOG_ERROR("Doesn't make sense to set itrigger with " + "mie_bits=0 and without nmi."); + return ERROR_FAIL; + } else if (!vs && !vu && !m && !s && !u) { + LOG_ERROR("Doesn't make sense to set itrigger without at " + "least one of vs, vu, m, s, or u."); + return ERROR_FAIL; + } + int result = maybe_add_trigger_t4(target, vs, vu, nmi, m, s, u, interrupts, ITRIGGER_UNIQUE_ID); + if (result != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to set requested itrigger."); + return result; + + } else if (!strcmp(CMD_ARGV[0], "clear")) { + if (CMD_ARGC != 1) { + LOG_ERROR("clear command takes no extra arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (find_first_trigger_by_id(target, ITRIGGER_UNIQUE_ID) < 0) { + LOG_TARGET_ERROR(target, "No itrigger is set. Nothing to clear."); + return ERROR_FAIL; + } + return remove_trigger(target, ITRIGGER_UNIQUE_ID); + + } else { + LOG_ERROR("First argument must be either 'set' or 'clear'."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + return ERROR_OK; +} + COMMAND_HANDLER(handle_repeat_read) { struct target *target = get_current_target(CMD_CTX); @@ -3590,6 +3711,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, + { + .name = "itrigger", + .handler = riscv_itrigger, + .mode = COMMAND_EXEC, + .usage = "set [vs] [vu] [nmi] [m] [s] [u] |clear", + .help = "Set or clear a single interrupt trigger." + }, COMMAND_REGISTRATION_DONE }; @@ -4133,6 +4261,10 @@ int riscv_enumerate_triggers(struct target *target) if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; + case CSR_TDATA1_TYPE_ITRIGGER: + if (tdata1 & CSR_ITRIGGER_DMODE(riscv_xlen(target))) + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + break; } r->trigger_tinfo[t] = 1 << type; } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 657dafb42..3709c39f3 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -124,8 +124,10 @@ typedef struct { /* record the tinfo of each trigger */ unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS]; - /* For each physical trigger, contains -1 if the hwbp is available, or the - * unique_id of the breakpoint/watchpoint that is using it. + /* For each physical trigger contains: + * -1: the hwbp is available + * -4: The trigger is used by the itrigger command + * >= 0: unique_id of the breakpoint/watchpoint that is using it. * Note that in RTOS mode the triggers are the same across all harts the * target controls, while otherwise only a single hart is controlled. */ int trigger_unique_id[RISCV_MAX_HWBPS]; From 6c027e0df486fe4a8495541e9b321259c23c4a00 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 28 Dec 2022 11:47:50 -0800 Subject: [PATCH 3/5] target/riscv: Add `riscv etrigger` command. Change-Id: I7982231c5067b82e4ddb2999bca51dba06ccac7a Signed-off-by: Tim Newsome --- doc/openocd.texi | 15 +++++ src/target/riscv/riscv.c | 117 +++++++++++++++++++++++++++++++++++++++ src/target/riscv/riscv.h | 1 + 3 files changed, 133 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index b5a16a961..ab9dcaf33 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10723,6 +10723,21 @@ cleanly onto OpenOCD's notion of hardware breakpoints. These commands let you set those triggers directly. (It's also possible to do so by writing the appropriate CSRs.) +@deffn {Command} {riscv etrigger set} [@option{m}] [@option{s}] [@option{u}] [@option{vs}] [@option{vu}] exception_codes +Set an exception trigger (type 5) on the current target, which halts the target when it +fires. @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control +which execution modes the trigger fires in. @var{exception_codes} is a bit +field, where each bit corresponds to an exception code in mcause (defined in the +RISC-V Privileged Spec). The etrigger will fire on the exceptions whose bits are +set in @var{exception_codes}. + +For details on this trigger type, see the RISC-V Debug Specification. +@end deffn + +@deffn {Command} {riscv etrigger clear} +Clear the type 5 trigger that was set using @command{riscv etrigger set}. +@end deffn + @deffn {Command} {riscv itrigger set} [@option{m}] [@option{s}] [@option{u}] [@option{vs}] [@option{vu}] [@option{nmi}] mie_bits Set an interrupt trigger (type 4) on the current target, which halts the target when it fires. @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 6cd3a0198..117e7db8f 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -704,6 +704,37 @@ static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu, return ERROR_OK; } +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 idx, ret; + riscv_reg_t tdata1, tdata2; + + RISCV_INFO(r); + + 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); + tdata1 = set_field(tdata1, CSR_ETRIGGER_VS, vs); + tdata1 = set_field(tdata1, CSR_ETRIGGER_VU, vu); + tdata1 = set_field(tdata1, CSR_ETRIGGER_M, m); + tdata1 = set_field(tdata1, CSR_ETRIGGER_S, s); + tdata1 = set_field(tdata1, CSR_ETRIGGER_U, u); + + tdata2 = exception_codes; + + ret = find_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; +} + static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger) { int idx, ret; @@ -1126,6 +1157,9 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) case CSR_TDATA1_TYPE_ITRIGGER: hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target)); break; + case CSR_TDATA1_TYPE_ETRIGGER: + hit_mask = CSR_ETRIGGER_HIT(riscv_xlen(target)); + break; default: LOG_DEBUG("trigger %d has unknown type %d", i, type); continue; @@ -3294,6 +3328,78 @@ COMMAND_HANDLER(riscv_itrigger) return ERROR_OK; } +COMMAND_HANDLER(riscv_etrigger) +{ + if (CMD_ARGC < 1) { + LOG_ERROR("Command takes at least 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + const int ETRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ETRIGGER; + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (!strcmp(CMD_ARGV[0], "set")) { + if (find_first_trigger_by_id(target, ETRIGGER_UNIQUE_ID) >= 0) { + LOG_TARGET_ERROR(target, "An etrigger is already set, and OpenOCD " + "doesn't support setting more than one at a time."); + return ERROR_FAIL; + } + bool vs = false; + bool vu = false; + bool m = false; + bool s = false; + bool u = false; + riscv_reg_t exception_codes = 0; + + for (unsigned int i = 1; i < CMD_ARGC; i++) { + if (!strcmp(CMD_ARGV[i], "vs")) + vs = true; + else if (!strcmp(CMD_ARGV[i], "vu")) + vu = true; + else if (!strcmp(CMD_ARGV[i], "m")) + m = true; + else if (!strcmp(CMD_ARGV[i], "s")) + s = true; + else if (!strcmp(CMD_ARGV[i], "u")) + u = true; + else + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], exception_codes); + } + if (exception_codes == 0) { + LOG_ERROR("Doesn't make sense to set etrigger with " + "exception_codes=0."); + return ERROR_FAIL; + } else if (!vs && !vu && !m && !s && !u) { + LOG_ERROR("Doesn't make sense to set etrigger without at " + "least one of vs, vu, m, s, or u."); + return ERROR_FAIL; + } + int result = maybe_add_trigger_t5(target, vs, vu, m, s, u, exception_codes, ETRIGGER_UNIQUE_ID); + if (result != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to set requested etrigger."); + return result; + + } else if (!strcmp(CMD_ARGV[0], "clear")) { + if (CMD_ARGC != 1) { + LOG_ERROR("clear command takes no extra arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (find_first_trigger_by_id(target, ETRIGGER_UNIQUE_ID) < 0) { + LOG_TARGET_ERROR(target, "No etrigger is set. Nothing to clear."); + return ERROR_FAIL; + } + return remove_trigger(target, ETRIGGER_UNIQUE_ID); + + } else { + LOG_ERROR("First argument must be either 'set' or 'clear'."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + return ERROR_OK; +} + COMMAND_HANDLER(handle_repeat_read) { struct target *target = get_current_target(CMD_CTX); @@ -3711,6 +3817,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, + { + .name = "etrigger", + .handler = riscv_etrigger, + .mode = COMMAND_EXEC, + .usage = "set [vs] [vu] [m] [s] [u] |clear", + .help = "Set or clear a single exception trigger." + }, { .name = "itrigger", .handler = riscv_itrigger, @@ -4265,6 +4378,10 @@ int riscv_enumerate_triggers(struct target *target) if (tdata1 & CSR_ITRIGGER_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; + case CSR_TDATA1_TYPE_ETRIGGER: + if (tdata1 & CSR_ETRIGGER_DMODE(riscv_xlen(target))) + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + break; } r->trigger_tinfo[t] = 1 << type; } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 3709c39f3..f8381b9e0 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -127,6 +127,7 @@ typedef struct { /* For each physical trigger contains: * -1: the hwbp is available * -4: The trigger is used by the itrigger command + * -5: The trigger is used by the etrigger command * >= 0: unique_id of the breakpoint/watchpoint that is using it. * Note that in RTOS mode the triggers are the same across all harts the * target controls, while otherwise only a single hart is controlled. */ From 9efa7775d4a388719b3bc16d79ac5d294eba537a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 2 Jan 2023 13:53:56 -0800 Subject: [PATCH 4/5] target/riscv: Read back tdata2 in set_trigger() Change-Id: I2a9271c66565a4c93de3322e14be8b75577ed1b6 Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 117e7db8f..dd5eb71c9 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -520,7 +520,7 @@ static int find_first_trigger_by_id(struct target *target, int unique_id) static int set_trigger(struct target *target, int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask) { - riscv_reg_t tdata1_rb; + riscv_reg_t tdata1_rb, tdata2_rb; if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK) return ERROR_FAIL; if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK) @@ -528,16 +528,26 @@ static int set_trigger(struct target *target, int idx, riscv_reg_t tdata1, riscv if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; if ((tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask)) { - LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + LOG_TARGET_DEBUG(target, + "Trigger %u doesn't support what we need; After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; tdata1_ignore_mask=0x%" PRIx64, - tdata1, tdata1_rb, tdata1_ignore_mask); + idx, tdata1, tdata1_rb, tdata1_ignore_mask); riscv_set_register(target, GDB_REGNO_TDATA1, 0); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK) return ERROR_FAIL; + if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK) + return ERROR_FAIL; + if (tdata2 != tdata2_rb) { + LOG_TARGET_DEBUG(target, + "Trigger %u doesn't support what we need; wrote 0x%" + PRIx64 " to tdata2 but read back 0x%" PRIx64, + idx, tdata2, tdata2_rb); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } return ERROR_OK; } From d2ebfc87702106ce29869fd688f188e0c238ce97 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 3 Jan 2023 10:08:18 -0800 Subject: [PATCH 5/5] target/riscv: Use unsigned int for trigger indexes. Change-Id: I1f7cf3a5c8b86f3d6825f45a67ff05822ea67d28 Signed-off-by: Tim Newsome --- src/target/riscv/riscv.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index dd5eb71c9..1bda998d1 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -476,7 +476,7 @@ static bool can_use_napot_match(struct trigger *trigger, riscv_reg_t *tdata2) return false; } -static int find_trigger(struct target *target, int type, bool chained, int *idx) +static int find_trigger(struct target *target, int type, bool chained, unsigned int *idx) { RISCV_INFO(r); @@ -517,7 +517,7 @@ static int find_first_trigger_by_id(struct target *target, int unique_id) return -1; } -static int set_trigger(struct target *target, int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, +static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask) { riscv_reg_t tdata1_rb, tdata2_rb; @@ -553,7 +553,7 @@ static int set_trigger(struct target *target, int idx, riscv_reg_t tdata1, riscv static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) { - int idx, ret; + int ret; riscv_reg_t tdata1, tdata2; RISCV_INFO(r); @@ -568,6 +568,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) const uint32_t bpcontrol_bpmatch = 0xf << 7; const uint32_t bpcontrol_bpaction = 0xff << 11; + unsigned int idx; ret = find_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx); if (ret != ERROR_OK) return ret; @@ -599,7 +600,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger) { - int idx, ret; + int ret; riscv_reg_t tdata1, tdata2; RISCV_INFO(r); @@ -622,6 +623,7 @@ static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger) if (!can_use_napot_match(trigger, &tdata2)) goto MATCH_GE_LT; + unsigned int idx; ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx); if (ret != ERROR_OK) return ret; @@ -686,7 +688,7 @@ 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 idx, ret; + int ret; riscv_reg_t tdata1, tdata2; RISCV_INFO(r); @@ -704,6 +706,7 @@ static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu, tdata2 = interrupts; + unsigned int idx; ret = find_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx); if (ret != ERROR_OK) return ret; @@ -718,7 +721,7 @@ 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 idx, ret; + int ret; riscv_reg_t tdata1, tdata2; RISCV_INFO(r); @@ -735,6 +738,7 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu, tdata2 = exception_codes; + unsigned int idx; ret = find_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx); if (ret != ERROR_OK) return ret; @@ -747,7 +751,7 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu, static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger) { - int idx, ret; + int ret; riscv_reg_t tdata1, tdata2; RISCV_INFO(r); @@ -769,6 +773,7 @@ static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger) if (!can_use_napot_match(trigger, &tdata2)) goto MATCH_GE_LT; + unsigned int idx; ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx); if (ret != ERROR_OK) return ret;