riscv/target: Replace is_halted() with get_hart_state() (#756)
Prep work for handling unavailable harts. Change-Id: I9c00ed4cdad8edeaa5a13fbec7f88f40d8af9028 Signed-off-by: Tim Newsome <tim@sifive.com> Signed-off-by: Tim Newsome <tim@sifive.com>
This commit is contained in:
parent
61f183fb25
commit
88a629c017
|
@ -46,7 +46,6 @@ 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_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,
|
||||
riscv_insn_t d);
|
||||
|
@ -1307,8 +1306,7 @@ static int register_write_direct(struct target *target, unsigned number,
|
|||
|
||||
int result = register_write_abstract(target, number, value,
|
||||
register_size(target, number));
|
||||
if (result == ERROR_OK || !has_sufficient_progbuf(target, 2) ||
|
||||
!riscv_is_halted(target))
|
||||
if (result == ERROR_OK || !has_sufficient_progbuf(target, 2))
|
||||
return result;
|
||||
|
||||
struct riscv_program program;
|
||||
|
@ -1717,7 +1715,10 @@ static int examine(struct target *target)
|
|||
if (dm013_select_hart(target, info->index) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
bool halted = riscv_is_halted(target);
|
||||
enum riscv_hart_state state;
|
||||
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
bool halted = (state == RISCV_STATE_HALTED);
|
||||
if (!halted) {
|
||||
r->prepped = true;
|
||||
if (riscv013_halt_go(target) != ERROR_OK) {
|
||||
|
@ -2298,6 +2299,50 @@ static int sample_memory(struct target *target,
|
|||
return sample_memory_bus_v1(target, buf, config, until_ms);
|
||||
}
|
||||
|
||||
static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
if (dm013_select_target(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
uint32_t dmstatus;
|
||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) {
|
||||
LOG_TARGET_INFO(target, "Hart unexpectedly reset!");
|
||||
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
|
||||
DM_DMCONTROL_ACKHAVERESET;
|
||||
dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
|
||||
/* If we had been halted when we reset, request another halt. If we
|
||||
* ended up running out of reset, then the user will (hopefully) get a
|
||||
* message that a reset happened, that the target is running, and then
|
||||
* that it is halted again once the request goes through.
|
||||
*/
|
||||
if (target->state == TARGET_HALTED)
|
||||
dmcontrol |= DM_DMCONTROL_HALTREQ;
|
||||
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
||||
}
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ALLNONEXISTENT)) {
|
||||
*state = RISCV_STATE_NON_EXISTENT;
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
|
||||
*state = RISCV_STATE_UNAVAILABLE;
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) {
|
||||
*state = RISCV_STATE_HALTED;
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) {
|
||||
*state = RISCV_STATE_RUNNING;
|
||||
return ERROR_OK;
|
||||
}
|
||||
LOG_TARGET_ERROR(target, "Couldn't determine state. dmstatus=0x%x", dmstatus);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int init_target(struct command_context *cmd_ctx,
|
||||
struct target *target)
|
||||
{
|
||||
|
@ -2309,7 +2354,7 @@ static int init_target(struct command_context *cmd_ctx,
|
|||
generic_info->get_register_buf = &riscv013_get_register_buf;
|
||||
generic_info->set_register_buf = &riscv013_set_register_buf;
|
||||
generic_info->select_target = &dm013_select_target;
|
||||
generic_info->is_halted = &riscv013_is_halted;
|
||||
generic_info->get_hart_state = &riscv013_get_hart_state;
|
||||
generic_info->resume_go = &riscv013_resume_go;
|
||||
generic_info->step_current_hart = &riscv013_step_current_hart;
|
||||
generic_info->on_halt = &riscv013_on_halt;
|
||||
|
@ -4310,37 +4355,6 @@ static int riscv013_on_halt(struct target *target)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static bool riscv013_is_halted(struct target *target)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
|
||||
uint32_t dmstatus;
|
||||
if (dm013_select_target(target) != ERROR_OK)
|
||||
return false;
|
||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||
return false;
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL))
|
||||
LOG_TARGET_ERROR(target, "Hart is unavailable.");
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT))
|
||||
LOG_TARGET_ERROR(target, "Hart doesn't exist.");
|
||||
if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) {
|
||||
LOG_TARGET_INFO(target, "Hart unexpectedly reset!");
|
||||
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
|
||||
DM_DMCONTROL_ACKHAVERESET;
|
||||
dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
|
||||
/* If we had been halted when we reset, request another halt. If we
|
||||
* ended up running out of reset, then the user will (hopefully) get a
|
||||
* message that a reset happened, that the target is running, and then
|
||||
* that it is halted again once the request goes through.
|
||||
*/
|
||||
if (target->state == TARGET_HALTED)
|
||||
dmcontrol |= DM_DMCONTROL_HALTREQ;
|
||||
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
||||
}
|
||||
return get_field(dmstatus, DM_DMSTATUS_ALLHALTED);
|
||||
}
|
||||
|
||||
static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
|
||||
{
|
||||
riscv_reg_t dcsr;
|
||||
|
|
|
@ -1201,7 +1201,7 @@ static int old_or_new_riscv_step(struct target *target, int current,
|
|||
{
|
||||
RISCV_INFO(r);
|
||||
LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
|
||||
if (!r->is_halted)
|
||||
if (!r->get_hart_state)
|
||||
return oldriscv_step(target, current, address, handle_breakpoints);
|
||||
else
|
||||
return riscv_openocd_step(target, current, address, handle_breakpoints);
|
||||
|
@ -1243,7 +1243,7 @@ static int oldriscv_poll(struct target *target)
|
|||
static int old_or_new_riscv_poll(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
if (!r->is_halted)
|
||||
if (!r->get_hart_state)
|
||||
return oldriscv_poll(target);
|
||||
else
|
||||
return riscv_openocd_poll(target);
|
||||
|
@ -1317,14 +1317,11 @@ int halt_prep(struct target *target)
|
|||
|
||||
LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target),
|
||||
target->debug_reason);
|
||||
if (riscv_is_halted(target)) {
|
||||
LOG_DEBUG("[%s] Hart is already halted (debug_reason=%d).",
|
||||
target_name(target), target->debug_reason);
|
||||
if (target->debug_reason == DBG_REASON_NOTHALTED) {
|
||||
enum riscv_halt_reason halt_reason = riscv_halt_reason(target);
|
||||
if (set_debug_reason(target, halt_reason) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
r->prepped = false;
|
||||
if (target->state == TARGET_HALTED) {
|
||||
LOG_TARGET_DEBUG(target, "Hart is already halted.");
|
||||
} else if (target->state == TARGET_UNAVAILABLE) {
|
||||
LOG_TARGET_DEBUG(target, "Hart is unavailable.");
|
||||
} else {
|
||||
if (r->halt_prep(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
@ -1338,7 +1335,10 @@ int riscv_halt_go_all_harts(struct target *target)
|
|||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
if (riscv_is_halted(target)) {
|
||||
enum riscv_hart_state state;
|
||||
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
if (state == RISCV_STATE_HALTED) {
|
||||
LOG_DEBUG("[%s] Hart is already halted.", target_name(target));
|
||||
} else {
|
||||
if (r->halt_go(target) != ERROR_OK)
|
||||
|
@ -1354,13 +1354,12 @@ int halt_go(struct target *target)
|
|||
{
|
||||
riscv_info_t *r = riscv_info(target);
|
||||
int result;
|
||||
if (!r->is_halted) {
|
||||
if (!r->get_hart_state) {
|
||||
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;
|
||||
|
||||
|
@ -1376,7 +1375,7 @@ int riscv_halt(struct target *target)
|
|||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
if (!r->is_halted) {
|
||||
if (!r->get_hart_state) {
|
||||
struct target_type *tt = get_target_type(target);
|
||||
return tt->halt(target);
|
||||
}
|
||||
|
@ -1547,7 +1546,7 @@ static int resume_prep(struct target *target, int current,
|
|||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (r->is_halted) {
|
||||
if (r->get_hart_state) {
|
||||
if (r->resume_prep(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -1567,7 +1566,7 @@ static int resume_go(struct target *target, int current,
|
|||
{
|
||||
riscv_info_t *r = riscv_info(target);
|
||||
int result;
|
||||
if (!r->is_halted) {
|
||||
if (!r->get_hart_state) {
|
||||
struct target_type *tt = get_target_type(target);
|
||||
result = tt->resume(target, current, address, handle_breakpoints,
|
||||
debug_execution);
|
||||
|
@ -2187,7 +2186,10 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid)
|
|||
|
||||
/* If OpenOCD thinks we're running but this hart is halted then it's time
|
||||
* to raise an event. */
|
||||
bool halted = riscv_is_halted(target);
|
||||
enum riscv_hart_state state;
|
||||
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
bool halted = (state == RISCV_STATE_HALTED);
|
||||
|
||||
if (halted && timeval_ms() - r->last_activity > 100) {
|
||||
/* If we've been idle for a while, flush the register cache. Just in case
|
||||
|
@ -3624,7 +3626,7 @@ static int riscv_resume_go_all_harts(struct target *target)
|
|||
RISCV_INFO(r);
|
||||
|
||||
LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state);
|
||||
if (riscv_is_halted(target)) {
|
||||
if (target->state == TARGET_HALTED) {
|
||||
if (r->resume_go(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
} else {
|
||||
|
@ -3687,7 +3689,7 @@ int riscv_step_rtos_hart(struct target *target)
|
|||
RISCV_INFO(r);
|
||||
LOG_DEBUG("[%s] stepping", target_name(target));
|
||||
|
||||
if (!riscv_is_halted(target)) {
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Hart isn't halted before single step!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -3695,7 +3697,7 @@ int riscv_step_rtos_hart(struct target *target)
|
|||
if (r->step_current_hart(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
r->on_halt(target);
|
||||
if (!riscv_is_halted(target)) {
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Hart was not halted after single step!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -3897,11 +3899,11 @@ int riscv_save_register(struct target *target, enum gdb_regno regid)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bool riscv_is_halted(struct target *target)
|
||||
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
assert(r->is_halted);
|
||||
return r->is_halted(target);
|
||||
assert(r->get_hart_state);
|
||||
return r->get_hart_state(target, state);
|
||||
}
|
||||
|
||||
enum riscv_halt_reason riscv_halt_reason(struct target *target)
|
||||
|
|
|
@ -65,6 +65,13 @@ enum riscv_isrmasking_mode {
|
|||
RISCV_ISRMASK_STEPONLY,
|
||||
};
|
||||
|
||||
enum riscv_hart_state {
|
||||
RISCV_STATE_NON_EXISTENT,
|
||||
RISCV_STATE_RUNNING,
|
||||
RISCV_STATE_HALTED,
|
||||
RISCV_STATE_UNAVAILABLE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct target *target;
|
||||
unsigned custom_number;
|
||||
|
@ -152,7 +159,7 @@ typedef struct {
|
|||
int (*set_register_buf)(struct target *target, int regno,
|
||||
const uint8_t *buf);
|
||||
int (*select_target)(struct target *target);
|
||||
bool (*is_halted)(struct target *target);
|
||||
int (*get_hart_state)(struct target *target, enum riscv_hart_state *state);
|
||||
/* 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. */
|
||||
|
@ -366,7 +373,7 @@ int riscv_flush_registers(struct target *target);
|
|||
|
||||
/* Checks the state of the current hart -- "is_halted" checks the actual
|
||||
* on-device register. */
|
||||
bool riscv_is_halted(struct target *target);
|
||||
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state);
|
||||
enum riscv_halt_reason riscv_halt_reason(struct target *target);
|
||||
|
||||
/* These helper functions let the generic program interface get target-specific
|
||||
|
|
Loading…
Reference in New Issue