Simultaneous halt (#372)
* WIP Change-Id: I4f50dced77e9ded4a58ab152824a841a73bc0dc1 * riscv_halt() only halt harts that are running. Progress towards simultaneous halt. Change-Id: I749b6d9ba5e77aa7aca4342c7af841312b78be0e * -rtos riscv passes. But dual gdb is failing again. Change-Id: I1747ba42ce3f3062f6e8c28a75ac40e17f80e980 * Dual gdb works again. -rtos riscv still works. Change-Id: Idddddda79e5918b26e181384def1a305ecceced2 * -rtos hwthread almost completely works. Change-Id: I845feb0bd93484e28ca8620f4760c234d4ce5310 * Maybe better? Change-Id: I669c67e83acf1b749bfb534d3b3c0915c129d686 * All three methods work. Change-Id: If77074fa43f6420d1ec9b594fe366415f5a41f2c * Fix hitting hardware triggers with `-rtos riscv`. Change-Id: I8d4600e1c66fa0e3b9d986b96a5973d09f40735c * Fix halting dual core E31. Change-Id: Ic2d885e027312b68e2f3c6854957fbfee09f814b * Not addressing this TODO right now. Change-Id: Ic7c0d32424068ae1de04d37d15a411c1957207c4 * Remove duplicate line. Change-Id: I14fe8d422f23c97afdaa20a02c0e3ab568219467
This commit is contained in:
parent
44a4deb373
commit
5cb2f200f8
|
@ -41,7 +41,8 @@ static int riscv013_get_register(struct target *target,
|
||||||
riscv_reg_t *value, int hid, int rid);
|
riscv_reg_t *value, int hid, int rid);
|
||||||
static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value);
|
static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value);
|
||||||
static int riscv013_select_current_hart(struct target *target);
|
static int riscv013_select_current_hart(struct target *target);
|
||||||
static int riscv013_halt_current_hart(struct target *target);
|
static int riscv013_halt_prep(struct target *target);
|
||||||
|
static int riscv013_halt_go(struct target *target);
|
||||||
static int riscv013_resume_go(struct target *target);
|
static int riscv013_resume_go(struct target *target);
|
||||||
static int riscv013_step_current_hart(struct target *target);
|
static int riscv013_step_current_hart(struct target *target);
|
||||||
static int riscv013_on_halt(struct target *target);
|
static int riscv013_on_halt(struct target *target);
|
||||||
|
@ -1586,7 +1587,7 @@ static int examine(struct target *target)
|
||||||
|
|
||||||
bool halted = riscv_is_halted(target);
|
bool halted = riscv_is_halted(target);
|
||||||
if (!halted) {
|
if (!halted) {
|
||||||
if (riscv013_halt_current_hart(target) != ERROR_OK) {
|
if (riscv013_halt_go(target) != ERROR_OK) {
|
||||||
LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i);
|
LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -1701,11 +1702,12 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
generic_info->set_register = &riscv013_set_register;
|
generic_info->set_register = &riscv013_set_register;
|
||||||
generic_info->select_current_hart = &riscv013_select_current_hart;
|
generic_info->select_current_hart = &riscv013_select_current_hart;
|
||||||
generic_info->is_halted = &riscv013_is_halted;
|
generic_info->is_halted = &riscv013_is_halted;
|
||||||
generic_info->halt_current_hart = &riscv013_halt_current_hart;
|
|
||||||
generic_info->resume_go = &riscv013_resume_go;
|
generic_info->resume_go = &riscv013_resume_go;
|
||||||
generic_info->step_current_hart = &riscv013_step_current_hart;
|
generic_info->step_current_hart = &riscv013_step_current_hart;
|
||||||
generic_info->on_halt = &riscv013_on_halt;
|
generic_info->on_halt = &riscv013_on_halt;
|
||||||
generic_info->resume_prep = &riscv013_resume_prep;
|
generic_info->resume_prep = &riscv013_resume_prep;
|
||||||
|
generic_info->halt_prep = &riscv013_halt_prep;
|
||||||
|
generic_info->halt_go = &riscv013_halt_go;
|
||||||
generic_info->on_step = &riscv013_on_step;
|
generic_info->on_step = &riscv013_on_step;
|
||||||
generic_info->halt_reason = &riscv013_halt_reason;
|
generic_info->halt_reason = &riscv013_halt_reason;
|
||||||
generic_info->read_debug_buffer = &riscv013_read_debug_buffer;
|
generic_info->read_debug_buffer = &riscv013_read_debug_buffer;
|
||||||
|
@ -2897,7 +2899,7 @@ struct target_type riscv013_target = {
|
||||||
.examine = examine,
|
.examine = examine,
|
||||||
|
|
||||||
.poll = &riscv_openocd_poll,
|
.poll = &riscv_openocd_poll,
|
||||||
.halt = &riscv_openocd_halt,
|
.halt = &riscv_halt,
|
||||||
.resume = &riscv_resume,
|
.resume = &riscv_resume,
|
||||||
.step = &riscv_openocd_step,
|
.step = &riscv_openocd_step,
|
||||||
|
|
||||||
|
@ -2985,42 +2987,6 @@ static int riscv013_select_current_hart(struct target *target)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_halt_current_hart(struct target *target)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
LOG_DEBUG("halting hart %d", r->current_hartid);
|
|
||||||
if (riscv_is_halted(target))
|
|
||||||
LOG_ERROR("Hart %d is already halted!", r->current_hartid);
|
|
||||||
|
|
||||||
/* Issue the halt command, and then wait for the current hart to halt. */
|
|
||||||
uint32_t dmcontrol;
|
|
||||||
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 1);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
|
||||||
for (size_t i = 0; i < 256; ++i)
|
|
||||||
if (riscv_is_halted(target))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!riscv_is_halted(target)) {
|
|
||||||
uint32_t dmstatus;
|
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
LOG_ERROR("unable to halt hart %d", r->current_hartid);
|
|
||||||
LOG_ERROR(" dmcontrol=0x%08x", dmcontrol);
|
|
||||||
LOG_ERROR(" dmstatus =0x%08x", dmstatus);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 0);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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, bool *use_hasel)
|
||||||
|
@ -3047,6 +3013,7 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
|
||||||
riscv013_info_t *info = get_info(t);
|
riscv013_info_t *info = get_info(t);
|
||||||
unsigned index = info->index;
|
unsigned index = info->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, r->prepped);
|
||||||
|
r->selected = r->prepped;
|
||||||
if (r->prepped) {
|
if (r->prepped) {
|
||||||
hawindow[index / 32] |= 1 << (index % 32);
|
hawindow[index / 32] |= 1 << (index % 32);
|
||||||
r->prepped = false;
|
r->prepped = false;
|
||||||
|
@ -3072,6 +3039,63 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int riscv013_halt_prep(struct target *target)
|
||||||
|
{
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int riscv013_halt_go(struct target *target)
|
||||||
|
{
|
||||||
|
bool use_hasel = false;
|
||||||
|
if (!riscv_rtos_enabled(target)) {
|
||||||
|
if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RISCV_INFO(r);
|
||||||
|
LOG_DEBUG("halting hart %d", r->current_hartid);
|
||||||
|
|
||||||
|
/* Issue the halt command, and then wait for the current hart to halt. */
|
||||||
|
uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_HALTREQ;
|
||||||
|
if (use_hasel)
|
||||||
|
dmcontrol |= DMI_DMCONTROL_HASEL;
|
||||||
|
dmcontrol = set_hartsel(dmcontrol, r->current_hartid);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
||||||
|
for (size_t i = 0; i < 256; ++i)
|
||||||
|
if (riscv_is_halted(target))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!riscv_is_halted(target)) {
|
||||||
|
uint32_t dmstatus;
|
||||||
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
LOG_ERROR("unable to halt hart %d", r->current_hartid);
|
||||||
|
LOG_ERROR(" dmcontrol=0x%08x", dmcontrol);
|
||||||
|
LOG_ERROR(" dmstatus =0x%08x", dmstatus);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 0);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
||||||
|
|
||||||
|
if (use_hasel) {
|
||||||
|
target_list_t *entry;
|
||||||
|
dm013_info_t *dm = get_dm(target);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* The "else" case is handled in halt_go(). */
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int riscv013_resume_go(struct target *target)
|
static int riscv013_resume_go(struct target *target)
|
||||||
{
|
{
|
||||||
bool use_hasel = false;
|
bool use_hasel = false;
|
||||||
|
@ -3634,7 +3658,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||||
|
|
||||||
if (step) {
|
if (step) {
|
||||||
LOG_ERROR(" was stepping, halting");
|
LOG_ERROR(" was stepping, halting");
|
||||||
riscv013_halt_current_hart(target);
|
riscv_halt(target);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3731,7 +3755,7 @@ int riscv013_test_compliance(struct target *target)
|
||||||
/* TODO: test that hamask registers exist if hasel does. */
|
/* TODO: test that hamask registers exist if hasel does. */
|
||||||
|
|
||||||
/* haltreq */
|
/* haltreq */
|
||||||
COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
|
COMPLIANCE_MUST_PASS(riscv_halt(target));
|
||||||
/* This bit is not actually readable according to the spec, so nothing to check.*/
|
/* This bit is not actually readable according to the spec, so nothing to check.*/
|
||||||
|
|
||||||
/* DMSTATUS */
|
/* DMSTATUS */
|
||||||
|
@ -3742,7 +3766,7 @@ int riscv013_test_compliance(struct target *target)
|
||||||
COMPLIANCE_MUST_PASS(riscv_resume(target, true, 0, false, false));
|
COMPLIANCE_MUST_PASS(riscv_resume(target, true, 0, false, false));
|
||||||
|
|
||||||
/* Halt all harts again so the test can continue.*/
|
/* Halt all harts again so the test can continue.*/
|
||||||
COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
|
COMPLIANCE_MUST_PASS(riscv_halt(target));
|
||||||
|
|
||||||
/* HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. */
|
/* HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. */
|
||||||
uint32_t hartinfo;
|
uint32_t hartinfo;
|
||||||
|
@ -4107,7 +4131,7 @@ int riscv013_test_compliance(struct target *target)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Halt every hart for any follow-up tests*/
|
/* Halt every hart for any follow-up tests*/
|
||||||
COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
|
COMPLIANCE_MUST_PASS(riscv_halt(target));
|
||||||
|
|
||||||
uint32_t failed_tests = total_tests - passed_tests;
|
uint32_t failed_tests = total_tests - passed_tests;
|
||||||
if (total_tests == passed_tests) {
|
if (total_tests == passed_tests) {
|
||||||
|
|
|
@ -431,12 +431,6 @@ static void riscv_deinit_target(struct target *target)
|
||||||
target->arch_info = NULL;
|
target->arch_info = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oldriscv_halt(struct target *target)
|
|
||||||
{
|
|
||||||
struct target_type *tt = get_target_type(target);
|
|
||||||
return tt->halt(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void trigger_from_breakpoint(struct trigger *trigger,
|
static void trigger_from_breakpoint(struct trigger *trigger,
|
||||||
const struct breakpoint *breakpoint)
|
const struct breakpoint *breakpoint)
|
||||||
{
|
{
|
||||||
|
@ -820,6 +814,8 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi
|
||||||
{
|
{
|
||||||
struct watchpoint *wp = target->watchpoints;
|
struct watchpoint *wp = target->watchpoints;
|
||||||
|
|
||||||
|
if (riscv_rtos_enabled(target))
|
||||||
|
riscv_set_current_hartid(target, target->rtos->current_thread - 1);
|
||||||
LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target));
|
LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target));
|
||||||
|
|
||||||
/*TODO instead of disassembling the instruction that we think caused the
|
/*TODO instead of disassembling the instruction that we think caused the
|
||||||
|
@ -957,13 +953,124 @@ static int old_or_new_riscv_poll(struct target *target)
|
||||||
return riscv_openocd_poll(target);
|
return riscv_openocd_poll(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int old_or_new_riscv_halt(struct target *target)
|
int halt_prep(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
if (r->is_halted == NULL)
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
return oldriscv_halt(target);
|
if (!riscv_hart_enabled(target, i))
|
||||||
else
|
continue;
|
||||||
return riscv_openocd_halt(target);
|
|
||||||
|
LOG_DEBUG("prep hart %d", i);
|
||||||
|
if (riscv_set_current_hartid(target, i) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
if (riscv_is_halted(target)) {
|
||||||
|
LOG_DEBUG("Hart %d is already halted.", i);
|
||||||
|
} else {
|
||||||
|
if (r->halt_prep(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
r->prepped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int riscv_halt_go_all_harts(struct target *target)
|
||||||
|
{
|
||||||
|
RISCV_INFO(r);
|
||||||
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
|
if (!riscv_hart_enabled(target, i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (riscv_set_current_hartid(target, i) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
if (riscv_is_halted(target)) {
|
||||||
|
LOG_DEBUG("Hart %d is already halted.", i);
|
||||||
|
} else {
|
||||||
|
if (r->halt_go(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
riscv_invalidate_register_cache(target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int halt_go(struct target *target)
|
||||||
|
{
|
||||||
|
riscv_info_t *r = riscv_info(target);
|
||||||
|
int result;
|
||||||
|
if (r->is_halted == NULL) {
|
||||||
|
struct target_type *tt = get_target_type(target);
|
||||||
|
result = tt->halt(target);
|
||||||
|
} else {
|
||||||
|
result = riscv_halt_go_all_harts(target);
|
||||||
|
}
|
||||||
|
target->state = TARGET_HALTED;
|
||||||
|
if (target->debug_reason == DBG_REASON_NOTHALTED)
|
||||||
|
target->debug_reason = DBG_REASON_DBGRQ;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int halt_finish(struct target *target)
|
||||||
|
{
|
||||||
|
return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
int riscv_halt(struct target *target)
|
||||||
|
{
|
||||||
|
RISCV_INFO(r);
|
||||||
|
|
||||||
|
if (r->is_halted == NULL) {
|
||||||
|
struct target_type *tt = get_target_type(target);
|
||||||
|
return tt->halt(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("[%d] halting all harts", target->coreid);
|
||||||
|
|
||||||
|
int result = ERROR_OK;
|
||||||
|
if (target->smp) {
|
||||||
|
for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
|
||||||
|
struct target *t = tlist->target;
|
||||||
|
if (halt_prep(t) != ERROR_OK)
|
||||||
|
result = ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
|
||||||
|
struct target *t = tlist->target;
|
||||||
|
riscv_info_t *i = riscv_info(t);
|
||||||
|
if (i->prepped) {
|
||||||
|
if (halt_go(t) != ERROR_OK)
|
||||||
|
result = ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
|
||||||
|
struct target *t = tlist->target;
|
||||||
|
if (halt_finish(t) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (halt_prep(target) != ERROR_OK)
|
||||||
|
result = ERROR_FAIL;
|
||||||
|
if (halt_go(target) != ERROR_OK)
|
||||||
|
result = ERROR_FAIL;
|
||||||
|
if (halt_finish(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (riscv_rtos_enabled(target)) {
|
||||||
|
if (r->rtos_hartid != -1) {
|
||||||
|
LOG_DEBUG("halt requested on RTOS hartid %d", r->rtos_hartid);
|
||||||
|
target->rtos->current_threadid = r->rtos_hartid + 1;
|
||||||
|
target->rtos->current_thread = r->rtos_hartid + 1;
|
||||||
|
} else
|
||||||
|
LOG_DEBUG("halt requested, but no known RTOS hartid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_assert_reset(struct target *target)
|
static int riscv_assert_reset(struct target *target)
|
||||||
|
@ -998,6 +1105,10 @@ int riscv_resume_prep_all_harts(struct target *target)
|
||||||
LOG_DEBUG(" hart %d requested resume, but was already resumed", i);
|
LOG_DEBUG(" hart %d requested resume, but was already resumed", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("[%d] mark as prepped", target->coreid);
|
||||||
|
r->prepped = true;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,6 +1198,7 @@ static int resume_finish(struct target *target)
|
||||||
register_cache_invalidate(target->reg_cache);
|
register_cache_invalidate(target->reg_cache);
|
||||||
|
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
return target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
return target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,7 +1434,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
LOG_ERROR("Algorithm timed out after %d ms.", timeout_ms);
|
LOG_ERROR("Algorithm timed out after %d ms.", timeout_ms);
|
||||||
LOG_ERROR(" now = 0x%08x", (uint32_t) now);
|
LOG_ERROR(" now = 0x%08x", (uint32_t) now);
|
||||||
LOG_ERROR(" start = 0x%08x", (uint32_t) start);
|
LOG_ERROR(" start = 0x%08x", (uint32_t) start);
|
||||||
oldriscv_halt(target);
|
riscv_halt(target);
|
||||||
old_or_new_riscv_poll(target);
|
old_or_new_riscv_poll(target);
|
||||||
return ERROR_TARGET_TIMEOUT;
|
return ERROR_TARGET_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -1401,6 +1513,7 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid)
|
||||||
} else if (target->state != TARGET_RUNNING && !halted) {
|
} else if (target->state != TARGET_RUNNING && !halted) {
|
||||||
LOG_DEBUG(" triggered running");
|
LOG_DEBUG(" triggered running");
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
return RPH_DISCOVERED_RUNNING;
|
return RPH_DISCOVERED_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1457,14 +1570,21 @@ int riscv_openocd_poll(struct target *target)
|
||||||
}
|
}
|
||||||
LOG_DEBUG(" hart %d halted", halted_hart);
|
LOG_DEBUG(" hart %d halted", halted_hart);
|
||||||
|
|
||||||
/* If we're here then at least one hart triggered. That means
|
target->state = TARGET_HALTED;
|
||||||
* we want to go and halt _every_ hart in the system, as that's
|
if (set_debug_reason(target, halted_hart) != ERROR_OK)
|
||||||
* the invariant we hold here. Some harts might have already
|
return ERROR_FAIL;
|
||||||
* halted (as we're either in single-step mode or they also
|
|
||||||
* triggered a breakpoint), so don't attempt to halt those
|
target->rtos->current_threadid = halted_hart + 1;
|
||||||
* harts. */
|
target->rtos->current_thread = halted_hart + 1;
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i)
|
riscv_set_rtos_hartid(target, halted_hart);
|
||||||
riscv_halt_one_hart(target, i);
|
|
||||||
|
/* If we're here then at least one hart triggered. That means we want
|
||||||
|
* to go and halt _every_ hart (configured with -rtos riscv) in the
|
||||||
|
* system, as that's the invariant we hold here. Some harts might have
|
||||||
|
* already halted (as we're either in single-step mode or they also
|
||||||
|
* triggered a breakpoint), so don't attempt to halt those harts.
|
||||||
|
* riscv_halt() will do all that for us. */
|
||||||
|
riscv_halt(target);
|
||||||
|
|
||||||
} else if (target->smp) {
|
} else if (target->smp) {
|
||||||
bool halt_discovered = false;
|
bool halt_discovered = false;
|
||||||
|
@ -1481,6 +1601,7 @@ int riscv_openocd_poll(struct target *target)
|
||||||
break;
|
break;
|
||||||
case RPH_DISCOVERED_RUNNING:
|
case RPH_DISCOVERED_RUNNING:
|
||||||
t->state = TARGET_RUNNING;
|
t->state = TARGET_RUNNING;
|
||||||
|
t->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
break;
|
break;
|
||||||
case RPH_DISCOVERED_HALTED:
|
case RPH_DISCOVERED_HALTED:
|
||||||
halt_discovered = true;
|
halt_discovered = true;
|
||||||
|
@ -1495,24 +1616,6 @@ int riscv_openocd_poll(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (halt_discovered) {
|
if (halt_discovered) {
|
||||||
LOG_DEBUG("Halt other targets in this SMP group.");
|
|
||||||
i = 0;
|
|
||||||
for (struct target_list *list = target->head; list != NULL;
|
|
||||||
list = list->next, i++) {
|
|
||||||
struct target *t = list->target;
|
|
||||||
riscv_info_t *r = riscv_info(t);
|
|
||||||
if (t->state != TARGET_HALTED) {
|
|
||||||
if (riscv_halt_one_hart(t, r->current_hartid) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
t->state = TARGET_HALTED;
|
|
||||||
if (set_debug_reason(t, r->current_hartid) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
newly_halted[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now that we have all our ducks in a row, tell the higher layers
|
|
||||||
* what just happened. */
|
|
||||||
i = 0;
|
i = 0;
|
||||||
for (struct target_list *list = target->head; list != NULL;
|
for (struct target_list *list = target->head; list != NULL;
|
||||||
list = list->next, i++) {
|
list = list->next, i++) {
|
||||||
|
@ -1520,6 +1623,9 @@ int riscv_openocd_poll(struct target *target)
|
||||||
if (newly_halted[i])
|
if (newly_halted[i])
|
||||||
target_call_event_callbacks(t, TARGET_EVENT_HALTED);
|
target_call_event_callbacks(t, TARGET_EVENT_HALTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Halt other targets in this SMP group.");
|
||||||
|
riscv_halt(target);
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
|
@ -1533,20 +1639,12 @@ int riscv_openocd_poll(struct target *target)
|
||||||
|
|
||||||
halted_hart = riscv_current_hartid(target);
|
halted_hart = riscv_current_hartid(target);
|
||||||
LOG_DEBUG(" hart %d halted", halted_hart);
|
LOG_DEBUG(" hart %d halted", halted_hart);
|
||||||
|
|
||||||
|
if (set_debug_reason(target, halted_hart) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
target->state = TARGET_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
|
||||||
if (set_debug_reason(target, halted_hart) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (riscv_rtos_enabled(target)) {
|
|
||||||
target->rtos->current_threadid = halted_hart + 1;
|
|
||||||
target->rtos->current_thread = halted_hart + 1;
|
|
||||||
riscv_set_rtos_hartid(target, halted_hart);
|
|
||||||
}
|
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
|
||||||
|
|
||||||
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
|
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
|
||||||
int retval;
|
int retval;
|
||||||
if (riscv_semihosting(target, &retval) != 0)
|
if (riscv_semihosting(target, &retval) != 0)
|
||||||
|
@ -1557,44 +1655,6 @@ int riscv_openocd_poll(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_openocd_halt(struct target *target)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
int result;
|
|
||||||
|
|
||||||
LOG_DEBUG("[%d] halting all harts", target->coreid);
|
|
||||||
|
|
||||||
if (target->smp) {
|
|
||||||
LOG_DEBUG("Halt other targets in this SMP group.");
|
|
||||||
struct target_list *targets = target->head;
|
|
||||||
result = ERROR_OK;
|
|
||||||
while (targets) {
|
|
||||||
struct target *t = targets->target;
|
|
||||||
targets = targets->next;
|
|
||||||
if (t->state != TARGET_HALTED) {
|
|
||||||
if (riscv_halt_all_harts(t) != ERROR_OK)
|
|
||||||
result = ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = riscv_halt_all_harts(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (riscv_rtos_enabled(target)) {
|
|
||||||
if (r->rtos_hartid != -1) {
|
|
||||||
LOG_DEBUG("halt requested on RTOS hartid %d", r->rtos_hartid);
|
|
||||||
target->rtos->current_threadid = r->rtos_hartid + 1;
|
|
||||||
target->rtos->current_thread = r->rtos_hartid + 1;
|
|
||||||
} else
|
|
||||||
LOG_DEBUG("halt requested, but no known RTOS hartid");
|
|
||||||
}
|
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
|
||||||
target->debug_reason = DBG_REASON_DBGRQ;
|
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_openocd_step(
|
int riscv_openocd_step(
|
||||||
struct target *target,
|
struct target *target,
|
||||||
int current,
|
int current,
|
||||||
|
@ -2178,7 +2238,7 @@ struct target_type riscv_target = {
|
||||||
/* poll current target status */
|
/* poll current target status */
|
||||||
.poll = old_or_new_riscv_poll,
|
.poll = old_or_new_riscv_poll,
|
||||||
|
|
||||||
.halt = old_or_new_riscv_halt,
|
.halt = riscv_halt,
|
||||||
.resume = riscv_resume,
|
.resume = riscv_resume,
|
||||||
.step = old_or_new_riscv_step,
|
.step = old_or_new_riscv_step,
|
||||||
|
|
||||||
|
@ -2228,36 +2288,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_halt_all_harts(struct target *target)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
|
||||||
if (!riscv_hart_enabled(target, i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
riscv_halt_one_hart(target, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_invalidate_register_cache(target);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_halt_one_hart(struct target *target, int hartid)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
LOG_DEBUG("halting hart %d", hartid);
|
|
||||||
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_is_halted(target)) {
|
|
||||||
LOG_DEBUG(" hart %d requested halt, but was already halted", hartid);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = r->halt_current_hart(target);
|
|
||||||
register_cache_invalidate(target->reg_cache);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int riscv_resume_go_all_harts(struct target *target)
|
static int riscv_resume_go_all_harts(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
|
@ -99,6 +99,8 @@ typedef struct {
|
||||||
|
|
||||||
/* This target has been prepped and is ready to step/resume. */
|
/* This target has been prepped and is ready to step/resume. */
|
||||||
bool prepped;
|
bool prepped;
|
||||||
|
/* This target was selected using hasel. */
|
||||||
|
bool selected;
|
||||||
|
|
||||||
/* Helper functions that target the various RISC-V debug spec
|
/* Helper functions that target the various RISC-V debug spec
|
||||||
* implementations. */
|
* implementations. */
|
||||||
|
@ -108,7 +110,6 @@ typedef struct {
|
||||||
uint64_t value);
|
uint64_t value);
|
||||||
int (*select_current_hart)(struct target *);
|
int (*select_current_hart)(struct target *);
|
||||||
bool (*is_halted)(struct target *target);
|
bool (*is_halted)(struct target *target);
|
||||||
int (*halt_current_hart)(struct target *);
|
|
||||||
/* Resume this target, as well as every other prepped target that can be
|
/* Resume this target, as well as every other prepped target that can be
|
||||||
* resumed near-simultaneously. Clear the prepped flag on any target that
|
* resumed near-simultaneously. Clear the prepped flag on any target that
|
||||||
* was resumed. */
|
* was resumed. */
|
||||||
|
@ -118,6 +119,8 @@ typedef struct {
|
||||||
/* Get this target as ready as possible to resume, without actually
|
/* Get this target as ready as possible to resume, without actually
|
||||||
* resuming. */
|
* resuming. */
|
||||||
int (*resume_prep)(struct target *target);
|
int (*resume_prep)(struct target *target);
|
||||||
|
int (*halt_prep)(struct target *target);
|
||||||
|
int (*halt_go)(struct target *target);
|
||||||
int (*on_step)(struct target *target);
|
int (*on_step)(struct target *target);
|
||||||
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
||||||
int (*write_debug_buffer)(struct target *target, unsigned index,
|
int (*write_debug_buffer)(struct target *target, unsigned index,
|
||||||
|
@ -179,7 +182,7 @@ void select_dmi_via_bscan(struct target *target);
|
||||||
/*** OpenOCD Interface */
|
/*** OpenOCD Interface */
|
||||||
int riscv_openocd_poll(struct target *target);
|
int riscv_openocd_poll(struct target *target);
|
||||||
|
|
||||||
int riscv_openocd_halt(struct target *target);
|
int riscv_halt(struct target *target);
|
||||||
|
|
||||||
int riscv_resume(
|
int riscv_resume(
|
||||||
struct target *target,
|
struct target *target,
|
||||||
|
@ -204,12 +207,6 @@ int riscv_openocd_deassert_reset(struct target *target);
|
||||||
/* Initializes the shared RISC-V structure. */
|
/* Initializes the shared RISC-V structure. */
|
||||||
void riscv_info_init(struct target *target, riscv_info_t *r);
|
void riscv_info_init(struct target *target, riscv_info_t *r);
|
||||||
|
|
||||||
/* Run control, possibly for multiple harts. The _all_harts versions resume
|
|
||||||
* all the enabled harts, which when running in RTOS mode is all the harts on
|
|
||||||
* the system. */
|
|
||||||
int riscv_halt_all_harts(struct target *target);
|
|
||||||
int riscv_halt_one_hart(struct target *target, int hartid);
|
|
||||||
|
|
||||||
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
|
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
|
||||||
* then the only hart. */
|
* then the only hart. */
|
||||||
int riscv_step_rtos_hart(struct target *target);
|
int riscv_step_rtos_hart(struct target *target);
|
||||||
|
|
Loading…
Reference in New Issue