aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rtos/riscv_debug.c2
-rw-r--r--src/target/riscv/riscv-011.c33
-rw-r--r--src/target/riscv/riscv-013.c174
-rw-r--r--src/target/riscv/riscv.c260
-rw-r--r--src/target/riscv/riscv.h22
5 files changed, 300 insertions, 191 deletions
diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c
index 4695e4e..726f326 100644
--- a/src/rtos/riscv_debug.c
+++ b/src/rtos/riscv_debug.c
@@ -259,7 +259,7 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet,
target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
target_call_event_callbacks(target, TARGET_EVENT_RESUME_START);
riscv_set_all_rtos_harts(target);
- riscv_openocd_resume(target, 1, 0, 0, 0);
+ riscv_resume(target, 1, 0, 0, 0);
target->state = TARGET_RUNNING;
gdb_set_frontend_state_running(connection);
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index eded862..aad5b8b 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -204,7 +204,6 @@ typedef struct {
* before the interrupt is cleared. */
unsigned int interrupt_high_delay;
- bool need_strict_step;
bool never_halted;
} riscv011_info_t;
@@ -1413,8 +1412,6 @@ static void deinit_target(struct target *target)
static int strict_step(struct target *target, bool announce)
{
- riscv011_info_t *info = get_info(target);
-
LOG_DEBUG("enter");
struct watchpoint *watchpoint = target->watchpoints;
@@ -1433,16 +1430,12 @@ static int strict_step(struct target *target, bool announce)
watchpoint = watchpoint->next;
}
- info->need_strict_step = false;
-
return ERROR_OK;
}
static int step(struct target *target, int current, target_addr_t address,
int handle_breakpoints)
{
- riscv011_info_t *info = get_info(target);
-
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
if (!current) {
@@ -1455,7 +1448,7 @@ static int step(struct target *target, int current, target_addr_t address,
return result;
}
- if (info->need_strict_step || handle_breakpoints) {
+ if (handle_breakpoints) {
int result = strict_step(target, true);
if (result != ERROR_OK)
return result;
@@ -1486,7 +1479,6 @@ static int examine(struct target *target)
}
RISCV_INFO(r);
- r->hart_count = 1;
riscv011_info_t *info = get_info(target);
info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS);
@@ -1848,9 +1840,6 @@ static int handle_halt(struct target *target, bool announce)
break;
case DCSR_CAUSE_HWBP:
target->debug_reason = DBG_REASON_WATCHPOINT;
- /* If we halted because of a data trigger, gdb doesn't know to do
- * the disable-breakpoints-step-enable-breakpoints dance. */
- info->need_strict_step = true;
break;
case DCSR_CAUSE_DEBUGINT:
target->debug_reason = DBG_REASON_DBGRQ;
@@ -1935,26 +1924,10 @@ static int riscv011_poll(struct target *target)
static int riscv011_resume(struct target *target, int current,
target_addr_t address, int handle_breakpoints, int debug_execution)
{
- riscv011_info_t *info = get_info(target);
-
+ RISCV_INFO(r);
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
- if (!current) {
- if (riscv_xlen(target) > 32) {
- LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
- riscv_xlen(target));
- }
- int result = register_write(target, GDB_REGNO_PC, address);
- if (result != ERROR_OK)
- return result;
- }
-
- if (info->need_strict_step || handle_breakpoints) {
- int result = strict_step(target, false);
- if (result != ERROR_OK)
- return result;
- }
-
+ r->prepped = false;
return resume(target, debug_execution, false);
}
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 1a5f212..d7bfac9 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -32,7 +32,8 @@
#define DMI_PROGBUF1 (DMI_PROGBUF0 + 1)
static int riscv013_on_step_or_resume(struct target *target, bool step);
-static int riscv013_step_or_resume_current_hart(struct target *target, bool step);
+static int riscv013_step_or_resume_current_hart(struct target *target,
+ bool step, bool use_hasel);
static void riscv013_clear_abstract_error(struct target *target);
/* Implementations of the functions in riscv_info_t. */
@@ -41,11 +42,11 @@ static int riscv013_get_register(struct target *target,
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_halt_current_hart(struct target *target);
-static int riscv013_resume_current_hart(struct target *target);
+static int riscv013_resume_go(struct target *target);
static int riscv013_step_current_hart(struct target *target);
static int riscv013_on_halt(struct target *target);
static int riscv013_on_step(struct target *target);
-static int riscv013_on_resume(struct target *target);
+static int riscv013_resume_prep(struct target *target);
static bool riscv013_is_halted(struct target *target);
static enum riscv_halt_reason riscv013_halt_reason(struct target *target);
static int riscv013_write_debug_buffer(struct target *target, unsigned index,
@@ -147,12 +148,16 @@ typedef enum {
typedef struct {
struct list_head list;
int abs_chain_position;
+
+ /* The number of harts connected to this DM. */
+ int hart_count;
/* Indicates we already reset this DM, so don't need to do it again. */
bool was_reset;
/* Targets that are connected to this DM. */
struct list_head target_list;
/* The currently selected hartid on this DM. */
int current_hartid;
+ bool hasel_supported;
} dm013_info_t;
typedef struct {
@@ -161,6 +166,8 @@ typedef struct {
} target_list_t;
typedef struct {
+ /* The indexed used to address this hart in its DM. */
+ unsigned index;
/* Number of address bits in the dbus register. */
unsigned abits;
/* Number of abstract command data registers. */
@@ -230,7 +237,7 @@ static riscv013_info_t *get_info(const struct target *target)
* global list of DMs. If it's not in there, then create one and initialize it
* to 0.
*/
-static dm013_info_t *get_dm(struct target *target)
+dm013_info_t *get_dm(struct target *target)
{
RISCV013_INFO(info);
if (info->dm)
@@ -248,9 +255,11 @@ static dm013_info_t *get_dm(struct target *target)
}
if (!dm) {
+ LOG_DEBUG("[%d] Allocating new DM", target->coreid);
dm = calloc(1, sizeof(dm013_info_t));
dm->abs_chain_position = abs_chain_position;
dm->current_hartid = -1;
+ dm->hart_count = -1;
INIT_LIST_HEAD(&dm->target_list);
list_add(&dm->list, &dm_list);
}
@@ -1397,6 +1406,8 @@ static int examine(struct target *target)
}
riscv013_info_t *info = get_info(target);
+ /* TODO: This won't be true if there are multiple DMs. */
+ info->index = target->coreid;
info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS);
info->dtmcs_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE);
@@ -1409,7 +1420,8 @@ static int examine(struct target *target)
}
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_HARTSELLO |
- DMI_DMCONTROL_HARTSELHI | DMI_DMCONTROL_DMACTIVE);
+ DMI_DMCONTROL_HARTSELHI | DMI_DMCONTROL_DMACTIVE |
+ DMI_DMCONTROL_HASEL);
uint32_t dmcontrol;
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
return ERROR_FAIL;
@@ -1420,6 +1432,8 @@ static int examine(struct target *target)
return ERROR_FAIL;
}
+ dm->hasel_supported = get_field(dmcontrol, DMI_DMCONTROL_HASEL);
+
uint32_t dmstatus;
if (dmstatus_read(target, &dmstatus, false) != ERROR_OK)
return ERROR_FAIL;
@@ -1483,10 +1497,35 @@ static int examine(struct target *target)
}
/* Before doing anything else we must first enumerate the harts. */
+ if (dm->hart_count < 0) {
+ for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) {
+ r->current_hartid = i;
+ if (riscv013_select_current_hart(target) != ERROR_OK)
+ return ERROR_FAIL;
+
+ uint32_t s;
+ if (dmstatus_read(target, &s, true) != ERROR_OK)
+ return ERROR_FAIL;
+ if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT))
+ break;
+ dm->hart_count = i + 1;
+
+ if (get_field(s, DMI_DMSTATUS_ANYHAVERESET))
+ dmi_write(target, DMI_DMCONTROL,
+ set_hartsel(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET, i));
+ }
+
+ LOG_DEBUG("Detected %d harts.", dm->hart_count);
+ }
+
+ if (dm->hart_count == 0) {
+ LOG_ERROR("No harts found!");
+ return ERROR_FAIL;
+ }
/* Don't call any riscv_* functions until after we've counted the number of
* cores and initialized registers. */
- for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) {
+ for (int i = 0; i < dm->hart_count; ++i) {
if (!riscv_rtos_enabled(target) && i != target->coreid)
continue;
@@ -1494,17 +1533,6 @@ static int examine(struct target *target)
if (riscv013_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
- uint32_t s;
- if (dmstatus_read(target, &s, true) != ERROR_OK)
- return ERROR_FAIL;
- if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT))
- break;
- r->hart_count = i + 1;
-
- if (get_field(s, DMI_DMSTATUS_ANYHAVERESET))
- dmi_write(target, DMI_DMCONTROL,
- set_hartsel(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET, i));
-
bool halted = riscv_is_halted(target);
if (!halted) {
if (riscv013_halt_current_hart(target) != ERROR_OK) {
@@ -1538,21 +1566,11 @@ static int examine(struct target *target)
r->misa[i]);
if (!halted)
- riscv013_resume_current_hart(target);
- }
-
- LOG_DEBUG("Enumerated %d harts", r->hart_count);
-
- if (r->hart_count == 0) {
- LOG_ERROR("No harts found!");
- return ERROR_FAIL;
+ riscv013_step_or_resume_current_hart(target, false, false);
}
target_set_examined(target);
- if (target->rtos)
- riscv_update_threads(target->rtos);
-
if (target->smp) {
bool haltgroup_supported;
if (set_haltgroup(target, &haltgroup_supported) != ERROR_OK)
@@ -1616,6 +1634,12 @@ int riscv013_authdata_write(struct target *target, uint32_t value)
return ERROR_OK;
}
+static int riscv013_hart_count(struct target *target)
+{
+ dm013_info_t *dm = get_dm(target);
+ return dm->hart_count;
+}
+
static int init_target(struct command_context *cmd_ctx,
struct target *target)
{
@@ -1627,10 +1651,10 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->select_current_hart = &riscv013_select_current_hart;
generic_info->is_halted = &riscv013_is_halted;
generic_info->halt_current_hart = &riscv013_halt_current_hart;
- generic_info->resume_current_hart = &riscv013_resume_current_hart;
+ generic_info->resume_go = &riscv013_resume_go;
generic_info->step_current_hart = &riscv013_step_current_hart;
generic_info->on_halt = &riscv013_on_halt;
- generic_info->on_resume = &riscv013_on_resume;
+ generic_info->resume_prep = &riscv013_resume_prep;
generic_info->on_step = &riscv013_on_step;
generic_info->halt_reason = &riscv013_halt_reason;
generic_info->read_debug_buffer = &riscv013_read_debug_buffer;
@@ -1646,6 +1670,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->dmi_write = &dmi_write;
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
generic_info->test_compliance = &riscv013_test_compliance;
+ generic_info->hart_count = &riscv013_hart_count;
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
if (!generic_info->version_specific)
return ERROR_FAIL;
@@ -2822,7 +2847,7 @@ struct target_type riscv013_target = {
.poll = &riscv_openocd_poll,
.halt = &riscv_openocd_halt,
- .resume = &riscv_openocd_resume,
+ .resume = &riscv_resume,
.step = &riscv_openocd_step,
.assert_reset = assert_reset,
@@ -2945,17 +2970,74 @@ static int riscv013_halt_current_hart(struct target *target)
return ERROR_OK;
}
-static int riscv013_resume_current_hart(struct target *target)
+/* Select all harts that were prepped and that are selectable, clearing the
+ * prepped flag on the harts that actually were selected. */
+static int select_prepped_harts(struct target *target, bool *use_hasel)
+{
+ dm013_info_t *dm = get_dm(target);
+ if (!dm->hasel_supported) {
+ RISCV_INFO(r);
+ r->prepped = false;
+ *use_hasel = false;
+ return ERROR_OK;
+ }
+
+ assert(dm->hart_count);
+ unsigned hawindow_count = (dm->hart_count + 31) / 32;
+ uint32_t hawindow[hawindow_count];
+
+ memset(hawindow, 0, sizeof(uint32_t) * hawindow_count);
+
+ target_list_t *entry;
+ unsigned total_selected = 0;
+ list_for_each_entry(entry, &dm->target_list, list) {
+ struct target *t = entry->target;
+ riscv_info_t *r = riscv_info(t);
+ riscv013_info_t *info = get_info(t);
+ unsigned index = info->index;
+ LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped);
+ if (r->prepped) {
+ hawindow[index / 32] |= 1 << (index % 32);
+ r->prepped = false;
+ total_selected++;
+ }
+ index++;
+ }
+
+ /* Don't use hasel if we only need to talk to one hart. */
+ if (total_selected <= 1) {
+ *use_hasel = false;
+ return ERROR_OK;
+ }
+
+ for (unsigned i = 0; i < hawindow_count; i++) {
+ if (dmi_write(target, DMI_HAWINDOWSEL, i) != ERROR_OK)
+ return ERROR_FAIL;
+ if (dmi_write(target, DMI_HAWINDOW, hawindow[i]) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ *use_hasel = true;
+ return ERROR_OK;
+}
+
+static int riscv013_resume_go(struct target *target)
{
- return riscv013_step_or_resume_current_hart(target, false);
+ bool use_hasel = false;
+ if (!riscv_rtos_enabled(target)) {
+ if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ return riscv013_step_or_resume_current_hart(target, false, use_hasel);
}
static int riscv013_step_current_hart(struct target *target)
{
- return riscv013_step_or_resume_current_hart(target, true);
+ return riscv013_step_or_resume_current_hart(target, true, false);
}
-static int riscv013_on_resume(struct target *target)
+static int riscv013_resume_prep(struct target *target)
{
return riscv013_on_step_or_resume(target, false);
}
@@ -3458,7 +3540,8 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
return riscv_set_register(target, GDB_REGNO_DCSR, dcsr);
}
-static int riscv013_step_or_resume_current_hart(struct target *target, bool step)
+static int riscv013_step_or_resume_current_hart(struct target *target,
+ bool step, bool use_hasel)
{
RISCV_INFO(r);
LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step);
@@ -3467,13 +3550,15 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step
return ERROR_FAIL;
}
- if (maybe_execute_fence_i(target) != ERROR_OK)
- return ERROR_FAIL;
-
/* Issue the resume command, and then wait for the current hart to resume. */
- uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE;
+ uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_RESUMEREQ;
+ if (use_hasel)
+ dmcontrol |= DMI_DMCONTROL_HASEL;
dmcontrol = set_hartsel(dmcontrol, r->current_hartid);
- dmi_write(target, DMI_DMCONTROL, dmcontrol | DMI_DMCONTROL_RESUMEREQ);
+ dmi_write(target, DMI_DMCONTROL, dmcontrol);
+
+ dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HASEL, 0);
+ dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0);
uint32_t dmstatus;
for (size_t i = 0; i < 256; ++i) {
@@ -3489,10 +3574,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step
return ERROR_OK;
}
+ dmi_write(target, DMI_DMCONTROL, dmcontrol);
+
LOG_ERROR("unable to resume hart %d", r->current_hartid);
- if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
- return ERROR_FAIL;
- LOG_ERROR(" dmcontrol=0x%08x", dmcontrol);
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
return ERROR_FAIL;
LOG_ERROR(" dmstatus =0x%08x", dmstatus);
@@ -3604,7 +3688,7 @@ int riscv013_test_compliance(struct target *target)
/* resumereq */
/* This bit is not actually readable according to the spec, so nothing to check.*/
- COMPLIANCE_MUST_PASS(riscv_resume_all_harts(target));
+ COMPLIANCE_MUST_PASS(riscv_resume(target, true, 0, false, false));
/* Halt all harts again so the test can continue.*/
COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index e027d00..5cdcc01 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -199,6 +199,8 @@ range_t *expose_csr;
/* Same, but for custom registers. */
range_t *expose_custom;
+static int riscv_resume_go_all_harts(struct target *target);
+
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
{
struct scan_field field;
@@ -846,16 +848,116 @@ static int riscv_deassert_reset(struct target *target)
return tt->deassert_reset(target);
}
+int riscv_resume_prep_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;
+
+ LOG_DEBUG("prep hart %d", i);
+ if (riscv_set_current_hartid(target, i) != ERROR_OK)
+ return ERROR_FAIL;
+ if (riscv_is_halted(target)) {
+ if (r->resume_prep(target) != ERROR_OK)
+ return ERROR_FAIL;
+ } else {
+ LOG_DEBUG(" hart %d requested resume, but was already resumed", i);
+ }
+ }
+ return ERROR_OK;
+}
-static int oldriscv_resume(struct target *target, int current, uint32_t address,
- int handle_breakpoints, int debug_execution)
+/**
+ * Get everything ready to resume.
+ */
+static int resume_prep(struct target *target, int current,
+ target_addr_t address, int handle_breakpoints, int debug_execution)
{
- struct target_type *tt = get_target_type(target);
- return tt->resume(target, current, address, handle_breakpoints,
- debug_execution);
+ RISCV_INFO(r);
+ LOG_DEBUG("[%d]", target->coreid);
+
+ if (!current)
+ riscv_set_register(target, GDB_REGNO_PC, address);
+
+ if (target->debug_reason == DBG_REASON_WATCHPOINT) {
+ /* To be able to run off a trigger, disable all the triggers, step, and
+ * then resume as usual. */
+ struct watchpoint *watchpoint = target->watchpoints;
+ bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0};
+
+ int i = 0;
+ int result = ERROR_OK;
+ while (watchpoint && result == ERROR_OK) {
+ LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set);
+ trigger_temporarily_cleared[i] = watchpoint->set;
+ if (watchpoint->set)
+ result = riscv_remove_watchpoint(target, watchpoint);
+ watchpoint = watchpoint->next;
+ i++;
+ }
+
+ if (result == ERROR_OK)
+ result = old_or_new_riscv_step(target, true, 0, false);
+
+ watchpoint = target->watchpoints;
+ i = 0;
+ while (watchpoint) {
+ LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]);
+ if (trigger_temporarily_cleared[i]) {
+ if (result == ERROR_OK)
+ result = riscv_add_watchpoint(target, watchpoint);
+ else
+ riscv_add_watchpoint(target, watchpoint);
+ }
+ watchpoint = watchpoint->next;
+ i++;
+ }
+
+ if (result != ERROR_OK)
+ return result;
+ }
+
+ if (r->is_halted) {
+ if (riscv_resume_prep_all_harts(target) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ LOG_DEBUG("[%d] mark as prepped", target->coreid);
+ r->prepped = true;
+
+ return ERROR_OK;
}
-static int old_or_new_riscv_resume(
+/**
+ * Resume all the harts that have been prepped, as close to instantaneous as
+ * possible.
+ */
+static int resume_go(struct target *target, int current,
+ target_addr_t address, int handle_breakpoints, int debug_execution)
+{
+ riscv_info_t *r = riscv_info(target);
+ int result;
+ if (r->is_halted == NULL) {
+ struct target_type *tt = get_target_type(target);
+ result = tt->resume(target, current, address, handle_breakpoints,
+ debug_execution);
+ } else {
+ result = riscv_resume_go_all_harts(target);
+ }
+
+ return result;
+}
+
+static int resume_finish(struct target *target)
+{
+ register_cache_invalidate(target->reg_cache);
+
+ target->state = TARGET_RUNNING;
+ return target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+}
+
+int riscv_resume(
struct target *target,
int current,
target_addr_t address,
@@ -863,31 +965,43 @@ static int old_or_new_riscv_resume(
int debug_execution
){
LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
+ int result = ERROR_OK;
if (target->smp) {
- struct target_list *targets = target->head;
- int result = ERROR_OK;
- while (targets) {
- struct target *t = targets->target;
- riscv_info_t *r = riscv_info(t);
- if (r->is_halted == NULL) {
- if (oldriscv_resume(t, current, address, handle_breakpoints,
+ for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ struct target *t = tlist->target;
+ if (resume_prep(t, current, address, handle_breakpoints,
+ debug_execution) != 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 (resume_go(t, current, address, handle_breakpoints,
debug_execution) != ERROR_OK)
result = ERROR_FAIL;
- } else {
- if (riscv_openocd_resume(t, current, address,
- handle_breakpoints, debug_execution) != ERROR_OK)
- result = ERROR_FAIL;
}
- targets = targets->next;
}
- return result;
+
+ for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+ struct target *t = tlist->target;
+ if (resume_finish(t) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ } else {
+ if (resume_prep(target, current, address, handle_breakpoints,
+ debug_execution) != ERROR_OK)
+ result = ERROR_FAIL;
+ if (resume_go(target, current, address, handle_breakpoints,
+ debug_execution) != ERROR_OK)
+ result = ERROR_FAIL;
+ if (resume_finish(target) != ERROR_OK)
+ return ERROR_FAIL;
}
- RISCV_INFO(r);
- if (r->is_halted == NULL)
- return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution);
- else
- return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution);
+ return result;
}
static int riscv_select_current_hart(struct target *target)
@@ -1064,7 +1178,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
/* Run algorithm */
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
- if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK)
+ if (riscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK)
return ERROR_FAIL;
int64_t start = timeval_ms();
@@ -1348,68 +1462,6 @@ int riscv_openocd_halt(struct target *target)
return result;
}
-int riscv_openocd_resume(
- struct target *target,
- int current,
- target_addr_t address,
- int handle_breakpoints,
- int debug_execution)
-{
- LOG_DEBUG("debug_reason=%d", target->debug_reason);
-
- if (!current)
- riscv_set_register(target, GDB_REGNO_PC, address);
-
- if (target->debug_reason == DBG_REASON_WATCHPOINT) {
- /* To be able to run off a trigger, disable all the triggers, step, and
- * then resume as usual. */
- struct watchpoint *watchpoint = target->watchpoints;
- bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0};
-
- int i = 0;
- int result = ERROR_OK;
- while (watchpoint && result == ERROR_OK) {
- LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set);
- trigger_temporarily_cleared[i] = watchpoint->set;
- if (watchpoint->set)
- result = riscv_remove_watchpoint(target, watchpoint);
- watchpoint = watchpoint->next;
- i++;
- }
-
- if (result == ERROR_OK)
- result = riscv_step_rtos_hart(target);
-
- watchpoint = target->watchpoints;
- i = 0;
- while (watchpoint) {
- LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]);
- if (trigger_temporarily_cleared[i]) {
- if (result == ERROR_OK)
- result = riscv_add_watchpoint(target, watchpoint);
- else
- riscv_add_watchpoint(target, watchpoint);
- }
- watchpoint = watchpoint->next;
- i++;
- }
-
- if (result != ERROR_OK)
- return result;
- }
-
- int out = riscv_resume_all_harts(target);
- if (out != ERROR_OK) {
- LOG_ERROR("unable to resume all harts");
- return out;
- }
-
- register_cache_invalidate(target->reg_cache);
- target->state = TARGET_RUNNING;
- target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
- return out;
-}
-
int riscv_openocd_step(
struct target *target,
int current,
@@ -1963,7 +2015,7 @@ struct target_type riscv_target = {
.poll = old_or_new_riscv_poll,
.halt = old_or_new_riscv_halt,
- .resume = old_or_new_riscv_resume,
+ .resume = riscv_resume,
.step = old_or_new_riscv_step,
.assert_reset = riscv_assert_reset,
@@ -2040,34 +2092,28 @@ int riscv_halt_one_hart(struct target *target, int hartid)
return result;
}
-int riscv_resume_all_harts(struct target *target)
+static int riscv_resume_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;
- riscv_resume_one_hart(target, i);
+ LOG_DEBUG("resuming hart %d", i);
+ if (riscv_set_current_hartid(target, i) != ERROR_OK)
+ return ERROR_FAIL;
+ if (riscv_is_halted(target)) {
+ if (r->resume_go(target) != ERROR_OK)
+ return ERROR_FAIL;
+ } else {
+ LOG_DEBUG(" hart %d requested resume, but was already resumed", i);
+ }
}
riscv_invalidate_register_cache(target);
return ERROR_OK;
}
-int riscv_resume_one_hart(struct target *target, int hartid)
-{
- RISCV_INFO(r);
- LOG_DEBUG("resuming 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 resume, but was already resumed", hartid);
- return ERROR_OK;
- }
-
- r->on_resume(target);
- return r->resume_current_hart(target);
-}
-
int riscv_step_rtos_hart(struct target *target)
{
RISCV_INFO(r);
@@ -2190,9 +2236,9 @@ int riscv_count_harts(struct target *target)
if (target == NULL)
return 1;
RISCV_INFO(r);
- if (r == NULL)
+ if (r == NULL || r->hart_count == NULL)
return 1;
- return r->hart_count;
+ return r->hart_count(target);
}
bool riscv_has_register(struct target *target, int hartid, int regid)
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index 59414fc..ade1bf0 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -46,9 +46,6 @@ typedef struct {
struct command_context *cmd_ctx;
void *version_specific;
- /* The number of harts on this system. */
- int hart_count;
-
/* The hart that the RTOS thinks is currently being debugged. */
int rtos_hartid;
@@ -100,6 +97,9 @@ typedef struct {
* delays, causing them to be relearned. Used for testing. */
int reset_delays_wait;
+ /* This target has been prepped and is ready to step/resume. */
+ bool prepped;
+
/* Helper functions that target the various RISC-V debug spec
* implementations. */
int (*get_register)(struct target *target,
@@ -109,10 +109,15 @@ typedef struct {
int (*select_current_hart)(struct target *);
bool (*is_halted)(struct target *target);
int (*halt_current_hart)(struct target *);
- int (*resume_current_hart)(struct target *target);
+ /* Resume this target, as well as every other prepped target that can be
+ * resumed near-simultaneously. Clear the prepped flag on any target that
+ * was resumed. */
+ int (*resume_go)(struct target *target);
int (*step_current_hart)(struct target *target);
int (*on_halt)(struct target *target);
- int (*on_resume)(struct target *target);
+ /* Get this target as ready as possible to resume, without actually
+ * resuming. */
+ int (*resume_prep)(struct target *target);
int (*on_step)(struct target *target);
enum riscv_halt_reason (*halt_reason)(struct target *target);
int (*write_debug_buffer)(struct target *target, unsigned index,
@@ -134,6 +139,9 @@ typedef struct {
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
int (*test_compliance)(struct target *target);
+
+ /* How many harts are attached to the DM that this target is attached to? */
+ int (*hart_count)(struct target *target);
} riscv_info_t;
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
@@ -163,7 +171,7 @@ int riscv_openocd_poll(struct target *target);
int riscv_openocd_halt(struct target *target);
-int riscv_openocd_resume(
+int riscv_resume(
struct target *target,
int current,
target_addr_t address,
@@ -191,8 +199,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r);
* the system. */
int riscv_halt_all_harts(struct target *target);
int riscv_halt_one_hart(struct target *target, int hartid);
-int riscv_resume_all_harts(struct target *target);
-int riscv_resume_one_hart(struct target *target, int hartid);
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
* then the only hart. */