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:
parent
c70862c202
commit
c089e6ae9a
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue