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>
This commit is contained in:
Tim Newsome 2022-10-27 14:48:03 -07:00
parent e69735db0b
commit bf15b00315
1 changed files with 26 additions and 3 deletions

View File

@ -4304,9 +4304,32 @@ static int riscv013_halt_go(struct target *target)
target_list_t *entry; target_list_t *entry;
list_for_each_entry(entry, &dm->target_list, list) { list_for_each_entry(entry, &dm->target_list, list) {
struct target *t = entry->target; struct target *t = entry->target;
t->state = TARGET_HALTED; uint32_t t_dmstatus;
if (t->debug_reason == DBG_REASON_NOTHALTED) if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED) ||
t->debug_reason = DBG_REASON_DBGRQ; 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(). */ /* The "else" case is handled in halt_go(). */