aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2023-06-05 10:50:15 -0700
committerTim Newsome <tim@sifive.com>2023-06-20 09:59:45 -0700
commitbf07ddef8a012961501faa136d3f574ae89ccf7e (patch)
treef2d3be60036b54c96d05c35c526dcf2617c5e84f /src/target
parentda5bf318b974ba9e7d1e5c2c24f9f070740fd5f8 (diff)
downloadriscv-openocd-bf07ddef8a012961501faa136d3f574ae89ccf7e.zip
riscv-openocd-bf07ddef8a012961501faa136d3f574ae89ccf7e.tar.gz
riscv-openocd-bf07ddef8a012961501faa136d3f574ae89ccf7e.tar.bz2
target/riscv: From tick(), set ebreak* if necessary.
This involves halting the target, which might have unintended side effects, but when the debugger is connected software breakpoints must trap to the debugger. Anything else is a terrible user experience. Change-Id: I1f7bb610eeeb054cc3042dc6bcfc16589ce12a31 Signed-off-by: Tim Newsome <tim@sifive.com>
Diffstat (limited to 'src/target')
-rw-r--r--src/target/riscv/riscv-013.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index b542a10..1e8a389 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -1596,6 +1596,69 @@ static int set_dcsr_ebreak(struct target *target, bool step)
return ERROR_OK;
}
+static int halt_set_dcsr_ebreak(struct target *target)
+{
+ RISCV_INFO(r);
+ RISCV013_INFO(info);
+ LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*");
+
+ /* Remove this hart from the halt group. This won't work on all targets
+ * because the debug spec allows halt groups to be hard-coded, but I
+ * haven't actually encountered those in the wild yet.
+ *
+ * There is a possible race condition when another hart halts, and
+ * this one is expected to also halt because it's supposed to be in the
+ * same halt group. Or when this hart is halted when that happens.
+ *
+ * A better solution might be to leave the halt groups alone, and track
+ * why we're halting when a halt occurs. When there are halt groups,
+ * that leads to extra halting if not all harts need to set dcsr.ebreak
+ * at the same time. It also makes for more complicated code.
+ *
+ * The perfect solution would be Quick Access, but I'm not aware of any
+ * hardware that implements it.
+ *
+ * We don't need a perfect solution, because we only get here when a
+ * hart spontaneously resets, or when it powers down and back up again.
+ * Those are both relatively rare. (At least I hope so. Maybe some
+ * design just powers each hart down for 90ms out of every 100ms)
+ */
+
+
+ if (info->haltgroup_supported) {
+ bool supported;
+ if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK)
+ return ERROR_FAIL;
+ if (!supported)
+ LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. "
+ "Some harts may be unexpectedly halted.");
+ }
+
+ int result = ERROR_OK;
+
+ r->prepped = true;
+ if (riscv013_halt_go(target) != ERROR_OK ||
+ set_dcsr_ebreak(target, false) != ERROR_OK ||
+ riscv013_step_or_resume_current_hart(target, false) != ERROR_OK) {
+ result = ERROR_FAIL;
+ } else {
+ target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ }
+
+ /* Add it back to the halt group. */
+ if (info->haltgroup_supported) {
+ bool supported;
+ if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK)
+ return ERROR_FAIL;
+ if (!supported)
+ LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. "
+ "Some harts may be unexpectedly halted.", target->smp);
+ }
+
+ return result;
+}
+
/*** OpenOCD target functions. ***/
static void deinit_target(struct target *target)
@@ -2488,6 +2551,16 @@ static int handle_became_unavailable(struct target *target,
return ERROR_OK;
}
+static int tick(struct target *target)
+{
+ RISCV013_INFO(info);
+ if (!info->dcsr_ebreak_is_set &&
+ target->state == TARGET_RUNNING &&
+ target_was_examined(target))
+ return halt_set_dcsr_ebreak(target);
+ return ERROR_OK;
+}
+
static int init_target(struct command_context *cmd_ctx,
struct target *target)
{
@@ -2525,6 +2598,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->print_info = &riscv013_print_info;
generic_info->handle_became_unavailable = &handle_became_unavailable;
+ generic_info->tick = &tick;
if (!generic_info->version_specific) {
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));