Properly track selecting multiple harts at once. (#743)

* Properly track selecting multiple harts at once.

use_hasel is a bit of a hack.

Change-Id: Ia589ebc16bca32038d915df9988361b88e940917
Signed-off-by: Tim Newsome <tim@sifive.com>

* Clarifying comment.

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Tim Newsome <tim@sifive.com>

* Rename set_hartsel to set_dmcontrol_hartsel

Change-Id: Iab28531281aa6fc604ec7d34974ed444ea9ea850

* Make set_dmcontrol_hartsel() more idiomatic.

Change-Id: I56a885043c515359e33b9c8a03aed637c81d1486

* Use constant for multiple harts instead of -1.

Change-Id: Iefeaf74202f2b4918d21f15f7ff7ca514175b8fb
Signed-off-by: Tim Newsome <tim@sifive.com>

Signed-off-by: Tim Newsome <tim@sifive.com>
Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
This commit is contained in:
Tim Newsome 2022-10-12 08:57:00 -07:00 committed by GitHub
parent bed28d5ec7
commit a50b280558
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 64 additions and 59 deletions

View File

@ -31,7 +31,7 @@
static int riscv013_on_step_or_resume(struct target *target, bool step); static int riscv013_on_step_or_resume(struct target *target, bool step);
static int riscv013_step_or_resume_current_hart(struct target *target, static int riscv013_step_or_resume_current_hart(struct target *target,
bool step, bool use_hasel); bool step);
static void riscv013_clear_abstract_error(struct target *target); static void riscv013_clear_abstract_error(struct target *target);
/* Implementations of the functions in riscv_info_t. */ /* Implementations of the functions in riscv_info_t. */
@ -129,6 +129,8 @@ typedef enum {
YNM_NO YNM_NO
} yes_no_maybe_t; } yes_no_maybe_t;
#define HART_INDEX_MULTIPLE -1
typedef struct { typedef struct {
struct list_head list; struct list_head list;
int abs_chain_position; int abs_chain_position;
@ -140,9 +142,7 @@ typedef struct {
/* Targets that are connected to this DM. */ /* Targets that are connected to this DM. */
struct list_head target_list; struct list_head target_list;
/* Contains the ID of the hart that is currently selected by this DM. /* Contains the ID of the hart that is currently selected by this DM.
* (If multiple harts are selected this is meaningless, and that corner case * If multiple harts are selected this is HART_INDEX_MULTIPLE. */
* is not currently handled well.)
*/
int current_hartid; int current_hartid;
bool hasel_supported; bool hasel_supported;
@ -216,6 +216,9 @@ typedef struct {
/* DM that provides access to this target. */ /* DM that provides access to this target. */
dm013_info_t *dm; dm013_info_t *dm;
/* This target was selected using hasel. */
bool selected;
} riscv013_info_t; } riscv013_info_t;
LIST_HEAD(dm_list); LIST_HEAD(dm_list);
@ -256,7 +259,7 @@ dm013_info_t *get_dm(struct target *target)
if (!dm) if (!dm)
return NULL; return NULL;
dm->abs_chain_position = abs_chain_position; dm->abs_chain_position = abs_chain_position;
dm->current_hartid = -1; dm->current_hartid = 0;
dm->hart_count = -1; dm->hart_count = -1;
INIT_LIST_HEAD(&dm->target_list); INIT_LIST_HEAD(&dm->target_list);
list_add(&dm->list, &dm_list); list_add(&dm->list, &dm_list);
@ -279,16 +282,21 @@ dm013_info_t *get_dm(struct target *target)
return dm; return dm;
} }
static uint32_t set_hartsel(uint32_t initial, uint32_t index) static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index)
{ {
initial &= ~DM_DMCONTROL_HARTSELLO; if (hart_index >= 0) {
initial &= ~DM_DMCONTROL_HARTSELHI; initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_SINGLE);
uint32_t index_lo = hart_index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1);
uint32_t index_lo = index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1); initial = set_field(initial, DM_DMCONTROL_HARTSELLO, index_lo);
initial |= index_lo << DM_DMCONTROL_HARTSELLO_OFFSET; uint32_t index_hi = hart_index >> DM_DMCONTROL_HARTSELLO_LENGTH;
uint32_t index_hi = index >> DM_DMCONTROL_HARTSELLO_LENGTH; assert(index_hi < (1 << DM_DMCONTROL_HARTSELHI_LENGTH));
assert(index_hi < 1 << DM_DMCONTROL_HARTSELHI_LENGTH); initial = set_field(initial, DM_DMCONTROL_HARTSELHI, index_hi);
initial |= index_hi << DM_DMCONTROL_HARTSELHI_OFFSET; } else if (hart_index == HART_INDEX_MULTIPLE) {
initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_MULTIPLE);
/* TODO: https://github.com/riscv/riscv-openocd/issues/748 */
initial = set_field(initial, DM_DMCONTROL_HARTSELLO, 0);
initial = set_field(initial, DM_DMCONTROL_HARTSELHI, 0);
}
return initial; return initial;
} }
@ -1684,7 +1692,7 @@ static int examine(struct target *target)
if (get_field(s, DM_DMSTATUS_ANYHAVERESET)) if (get_field(s, DM_DMSTATUS_ANYHAVERESET))
dmi_write(target, DM_DMCONTROL, dmi_write(target, DM_DMCONTROL,
set_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); set_dmcontrol_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i));
} }
LOG_DEBUG("Detected %d harts.", dm->hart_count); LOG_DEBUG("Detected %d harts.", dm->hart_count);
@ -1703,6 +1711,7 @@ static int examine(struct target *target)
bool halted = riscv_is_halted(target); bool halted = riscv_is_halted(target);
if (!halted) { if (!halted) {
r->prepped = true;
if (riscv013_halt_go(target) != ERROR_OK) { if (riscv013_halt_go(target) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()", LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()",
info->index); info->index);
@ -1761,7 +1770,7 @@ static int examine(struct target *target)
} }
if (!halted) if (!halted)
riscv013_step_or_resume_current_hart(target, false, false); riscv013_step_or_resume_current_hart(target, false);
if (target->smp) { if (target->smp) {
bool haltgroup_supported; bool haltgroup_supported;
@ -2357,7 +2366,7 @@ static int assert_reset(struct target *target)
/* Set haltreq for each hart. */ /* Set haltreq for each hart. */
uint32_t control = control_base; uint32_t control = control_base;
control = set_hartsel(control_base, info->index); control = set_dmcontrol_hartsel(control_base, info->index);
control = set_field(control, DM_DMCONTROL_HALTREQ, control = set_field(control, DM_DMCONTROL_HALTREQ,
target->reset_halt ? 1 : 0); target->reset_halt ? 1 : 0);
dmi_write(target, DM_DMCONTROL, control); dmi_write(target, DM_DMCONTROL, control);
@ -2368,7 +2377,7 @@ static int assert_reset(struct target *target)
} else { } else {
/* Reset just this hart. */ /* Reset just this hart. */
uint32_t control = set_hartsel(control_base, info->index); uint32_t control = set_dmcontrol_hartsel(control_base, info->index);
control = set_field(control, DM_DMCONTROL_HALTREQ, control = set_field(control, DM_DMCONTROL_HALTREQ,
target->reset_halt ? 1 : 0); target->reset_halt ? 1 : 0);
control = set_field(control, DM_DMCONTROL_NDMRESET, 1); control = set_field(control, DM_DMCONTROL_NDMRESET, 1);
@ -2398,7 +2407,7 @@ static int deassert_reset(struct target *target)
uint32_t control = 0; uint32_t control = 0;
control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); control = set_field(control, DM_DMCONTROL_DMACTIVE, 1);
dmi_write(target, DM_DMCONTROL, set_hartsel(control, info->index)); dmi_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(control, info->index));
uint32_t dmstatus; uint32_t dmstatus;
int dmi_busy_delay = info->dmi_busy_delay; int dmi_busy_delay = info->dmi_busy_delay;
@ -2410,7 +2419,7 @@ static int deassert_reset(struct target *target)
if (index != info->index) if (index != info->index)
continue; continue;
dmi_write(target, DM_DMCONTROL, dmi_write(target, DM_DMCONTROL,
set_hartsel(control, index)); set_dmcontrol_hartsel(control, index));
} else { } else {
index = info->index; index = info->index;
} }
@ -2449,7 +2458,7 @@ static int deassert_reset(struct target *target)
if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) {
/* Ack reset. */ /* Ack reset. */
dmi_write(target, DM_DMCONTROL, dmi_write(target, DM_DMCONTROL,
set_hartsel(control, index) | set_dmcontrol_hartsel(control, index) |
DM_DMCONTROL_ACKHAVERESET); DM_DMCONTROL_ACKHAVERESET);
} }
@ -4122,7 +4131,7 @@ static int dm013_select_hart(struct target *target, int hart_index)
return ERROR_OK; return ERROR_OK;
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE; uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE;
dmcontrol = set_hartsel(dmcontrol, hart_index); dmcontrol = set_dmcontrol_hartsel(dmcontrol, hart_index);
if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) { if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) {
/* Who knows what the state is? */ /* Who knows what the state is? */
dm->current_hartid = -2; dm->current_hartid = -2;
@ -4134,15 +4143,14 @@ static int dm013_select_hart(struct target *target, int hart_index)
/* Select all harts that were prepped and that are selectable, clearing the /* Select all harts that were prepped and that are selectable, clearing the
* prepped flag on the harts that actually were selected. */ * prepped flag on the harts that actually were selected. */
static int select_prepped_harts(struct target *target, bool *use_hasel) static int select_prepped_harts(struct target *target)
{ {
RISCV_INFO(r);
dm013_info_t *dm = get_dm(target); dm013_info_t *dm = get_dm(target);
if (!dm) if (!dm)
return ERROR_FAIL; return ERROR_FAIL;
if (!dm->hasel_supported) { if (!dm->hasel_supported) {
RISCV_INFO(r);
r->prepped = false; r->prepped = false;
*use_hasel = false;
dm013_select_target(target); dm013_select_target(target);
return ERROR_OK; return ERROR_OK;
} }
@ -4155,27 +4163,33 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
target_list_t *entry; target_list_t *entry;
unsigned total_selected = 0; unsigned total_selected = 0;
unsigned int selected_index = 0;
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;
riscv_info_t *r = riscv_info(t); riscv_info_t *info = riscv_info(t);
riscv013_info_t *info = get_info(t); riscv013_info_t *info_013 = get_info(t);
unsigned index = info->index; unsigned index = info_013->index;
LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped); LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, info->prepped);
r->selected = r->prepped; if (info->prepped) {
if (r->prepped) { info_013->selected = true;
hawindow[index / 32] |= 1 << (index % 32); hawindow[index / 32] |= 1 << (index % 32);
r->prepped = false; info->prepped = false;
total_selected++; total_selected++;
selected_index = index;
} }
index++;
} }
if (total_selected == 0) {
LOG_TARGET_ERROR(target, "No harts were prepped!");
return ERROR_FAIL;
} else if (total_selected == 1) {
/* Don't use hasel if we only need to talk to one hart. */ /* Don't use hasel if we only need to talk to one hart. */
if (total_selected <= 1) { return dm013_select_hart(target, selected_index);
*use_hasel = false;
return ERROR_OK;
} }
if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK)
return ERROR_FAIL;
for (unsigned i = 0; i < hawindow_count; i++) { for (unsigned i = 0; i < hawindow_count; i++) {
if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
@ -4183,7 +4197,6 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
return ERROR_FAIL; return ERROR_FAIL;
} }
*use_hasel = true;
return ERROR_OK; return ERROR_OK;
} }
@ -4194,19 +4207,18 @@ static int riscv013_halt_prep(struct target *target)
static int riscv013_halt_go(struct target *target) static int riscv013_halt_go(struct target *target)
{ {
RISCV013_INFO(info); dm013_info_t *dm = get_dm(target);
if (!dm)
return ERROR_FAIL;
bool use_hasel = false; if (select_prepped_harts(target) != ERROR_OK)
if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
LOG_TARGET_DEBUG(target, "halting hart"); LOG_TARGET_DEBUG(target, "halting hart");
/* Issue the halt command, and then wait for the current hart to halt. */ /* Issue the halt command, and then wait for the current hart to halt. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
if (use_hasel) dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid);
dmcontrol |= DM_DMCONTROL_HASEL;
dmcontrol = set_hartsel(dmcontrol, info->index);
dmi_write(target, DM_DMCONTROL, dmcontrol); dmi_write(target, DM_DMCONTROL, dmcontrol);
uint32_t dmstatus; uint32_t dmstatus;
for (size_t i = 0; i < 256; ++i) { for (size_t i = 0; i < 256; ++i) {
@ -4232,11 +4244,8 @@ static int riscv013_halt_go(struct target *target)
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0);
dmi_write(target, DM_DMCONTROL, dmcontrol); dmi_write(target, DM_DMCONTROL, dmcontrol);
if (use_hasel) { if (dm->current_hartid == HART_INDEX_MULTIPLE) {
target_list_t *entry; target_list_t *entry;
dm013_info_t *dm = get_dm(target);
if (!dm)
return ERROR_FAIL;
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; t->state = TARGET_HALTED;
@ -4251,16 +4260,15 @@ static int riscv013_halt_go(struct target *target)
static int riscv013_resume_go(struct target *target) static int riscv013_resume_go(struct target *target)
{ {
bool use_hasel = false; if (select_prepped_harts(target) != ERROR_OK)
if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
return riscv013_step_or_resume_current_hart(target, false, use_hasel); return riscv013_step_or_resume_current_hart(target, false);
} }
static int riscv013_step_current_hart(struct target *target) static int riscv013_step_current_hart(struct target *target)
{ {
return riscv013_step_or_resume_current_hart(target, true, false); return riscv013_step_or_resume_current_hart(target, true);
} }
static int riscv013_resume_prep(struct target *target) static int riscv013_resume_prep(struct target *target)
@ -4296,7 +4304,7 @@ static bool riscv013_is_halted(struct target *target)
/* TODO: Can we make this more obvious to eg. a gdb user? */ /* TODO: Can we make this more obvious to eg. a gdb user? */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
DM_DMCONTROL_ACKHAVERESET; DM_DMCONTROL_ACKHAVERESET;
dmcontrol = set_hartsel(dmcontrol, info->index); dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
/* If we had been halted when we reset, request another halt. If we /* If we had been halted when we reset, request another halt. If we
* ended up running out of reset, then the user will (hopefully) get a * ended up running out of reset, then the user will (hopefully) get a
* message that a reset happened, that the target is running, and then * message that a reset happened, that the target is running, and then
@ -4799,9 +4807,9 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
} }
static int riscv013_step_or_resume_current_hart(struct target *target, static int riscv013_step_or_resume_current_hart(struct target *target,
bool step, bool use_hasel) bool step)
{ {
if (!riscv_is_halted(target)) { if (target->state != TARGET_HALTED) {
LOG_TARGET_ERROR(target, "Hart is not halted!"); LOG_TARGET_ERROR(target, "Hart is not halted!");
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -4813,12 +4821,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
dm013_info_t *dm = get_dm(target); dm013_info_t *dm = get_dm(target);
/* Issue the resume command, and then wait for the current hart to resume. */ /* Issue the resume command, and then wait for the current hart to resume. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
if (use_hasel) dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid);
dmcontrol |= DM_DMCONTROL_HASEL;
dmcontrol = set_hartsel(dmcontrol, dm->current_hartid);
dmi_write(target, DM_DMCONTROL, dmcontrol); dmi_write(target, DM_DMCONTROL, dmcontrol);
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0);
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0);
uint32_t dmstatus; uint32_t dmstatus;