Support simultaneous resume using hasel (#364)

* Remove unnecessary 0.11 code.

Don't need need_strict_step anymore now that we have
riscv_hit_watchpoint().

Don't need 32-bit warning in riscv011_resume() now that address is a
target_address_t.

Change-Id: I375c023a7ec9f62d80b037ddb64d14526ba0a3dc

* WIP little refactor working towards hasel support.

Change-Id: Ie0b8dfd9e5ae2e36613fa00e14c3cd32749141bf

* More refactoring.

Change-Id: I083387c2ecff78ddfea3ed5078444732d77b909b

* More refactoring.

Change-Id: Icea1308499492da51354f89e1529353e8385f3a1

* Starting to work towards actual hasel changes.

Change-Id: If0df05ffa66cc58400b4855f9630a8b1bae3030e

* Implement simultaneous resume using hasel.

Change-Id: I97971d7564fdb159d2052393c8b82a2ffaa8833f

* Add support back for targets that don't have hasel.

Change-Id: I6d5439f0615d5d5333127d280e4f2642649a119a

* Make hasel work with >32 harts.

Change-Id: I3c55009d48bfc5dd62e3341df4e4bd21df2fe44f
This commit is contained in:
Tim Newsome 2019-04-03 12:13:09 -07:00 committed by GitHub
parent c70862c202
commit c089e6ae9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 301 additions and 192 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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)
{
return riscv013_step_or_resume_current_hart(target, false);
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)
{
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));

View File

@ -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);
}
static int oldriscv_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution)
int riscv_resume_prep_all_harts(struct target *target)
{
struct target_type *tt = get_target_type(target);
return tt->resume(target, current, address, handle_breakpoints,
debug_execution);
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 old_or_new_riscv_resume(
/**
* Get everything ready to resume.
*/
static int resume_prep(struct target *target, int current,
target_addr_t address, int handle_breakpoints, int 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;
}
/**
* 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)

View File

@ -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. */