aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2022-10-27 14:48:03 -0700
committerTim Newsome <tim@sifive.com>2022-11-23 12:59:58 -0800
commitbf15b003155a102bfd1479f6d17c2017f331d66a (patch)
tree5faaa9a67cec1aa4a85e2774687c6cc871b04141
parente69735db0bb5dc0932f741815dab00849bf10f9c (diff)
downloadriscv-openocd-bf15b003155a102bfd1479f6d17c2017f331d66a.zip
riscv-openocd-bf15b003155a102bfd1479f6d17c2017f331d66a.tar.gz
riscv-openocd-bf15b003155a102bfd1479f6d17c2017f331d66a.tar.bz2
target/riscv: Set correct target->state in riscv013_halt_go()
It used to set all states to halted, but that's not right for harts that are now unavailable. (It might be possible to call poll() at the right time instead of duplicating some of its code, but I didn't see an easy way to do that. The real requirement is that target->state is set to TARGET_UNAVAILABLE before TARGET_EVENT_HALTED is is sent in halt_finish(), because that's what triggers hwthread_update_threads(), which must know about unavailable harts so they can be hidden from gdb. Change-Id: I0a0bbdd4ec9ff8c9898e04045b84e1d2512c9336 Signed-off-by: Tim Newsome <tim@sifive.com>
-rw-r--r--src/target/riscv/riscv-013.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 5e54347..4172ff6 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -4304,9 +4304,32 @@ static int riscv013_halt_go(struct target *target)
target_list_t *entry;
list_for_each_entry(entry, &dm->target_list, list) {
struct target *t = entry->target;
- t->state = TARGET_HALTED;
- if (t->debug_reason == DBG_REASON_NOTHALTED)
- t->debug_reason = DBG_REASON_DBGRQ;
+ uint32_t t_dmstatus;
+ if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED) ||
+ get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
+ /* All harts are either halted or unavailable. No
+ * need to read dmstatus for each hart. */
+ t_dmstatus = dmstatus;
+ } else {
+ /* Only some harts were halted/unavailable. Read
+ * dmstatus for this one to see what its status
+ * is. */
+ riscv013_info_t *info = get_info(t);
+ dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
+ if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK)
+ return ERROR_FAIL;
+ dm->current_hartid = info->index;
+ if (dmi_read(target, &t_dmstatus, DM_DMSTATUS) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+ /* Set state for the current target based on its dmstatus. */
+ if (get_field(t_dmstatus, DM_DMSTATUS_ALLHALTED)) {
+ t->state = TARGET_HALTED;
+ if (t->debug_reason == DBG_REASON_NOTHALTED)
+ t->debug_reason = DBG_REASON_DBGRQ;
+ } else if (get_field(t_dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
+ t->state = TARGET_UNAVAILABLE;
+ }
}
}
/* The "else" case is handled in halt_go(). */