diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 33244a00a..57fc9d68a 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -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; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index e6ab3306e..5df672f4d 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -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) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index bd47e86a3..014d313b6 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -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