Compare commits

...

1 Commits

Author SHA1 Message Date
cgsfv 0c748e52c0 Improved handling of unavailable harts
Added more handling of unexamined harts

Added even more handling of unexamined harts

Added cleaner handling of unexamined harts

Fixing halt_set_dcsr_ebreak not setting hart explicitly enough

Adding riscv013_halt_current_hart function

Handling harts becoming available when halted

Extending handling of unavailable harts

Ensuring target is selected when resuming it

Making halt_set_dcsr_ebreak more robust

OK if target is unavailble after waiting for halt

Can also use progbuf only for dcsr_ebreak

Using progbuf for set_dcsr_break now works

Handle unavailability when deasserting reset
2024-05-06 09:44:55 -07:00
6 changed files with 343 additions and 214 deletions

View File

@ -71,6 +71,12 @@ static uint32_t jal(unsigned int rd, uint32_t imm)
return imm_j(imm) | inst_rd(rd) | MATCH_JAL;
}
static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
static uint32_t csrci(unsigned int csr, uint16_t imm)
{
return imm_i(csr) | inst_rs1(imm) | MATCH_CSRRCI;
}
static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
static uint32_t csrsi(unsigned int csr, uint16_t imm)
{
@ -143,6 +149,12 @@ static uint32_t csrr(unsigned int rd, unsigned int csr)
return imm_i(csr) | inst_rd(rd) | MATCH_CSRRS;
}
static uint32_t csrrc(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
static uint32_t csrrc(unsigned int rd, unsigned int rs, unsigned int csr)
{
return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRC;
}
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
{

View File

@ -16,6 +16,7 @@
#include "target/target.h"
#include "target/algorithm.h"
#include "target/target_type.h"
#include <target/smp.h>
#include <helper/log.h>
#include "jtag/jtag.h"
#include "target/register.h"
@ -31,7 +32,7 @@
#include "debug_reg_printer.h"
#include "field_helpers.h"
static int riscv013_on_step_or_resume(struct target *target, bool step);
static int riscv013_on_step_or_resume(struct target *target, bool skip, bool step);
static int riscv013_step_or_resume_current_hart(struct target *target,
bool step);
static int riscv013_clear_abstract_error(struct target *target);
@ -44,6 +45,7 @@ static int riscv013_set_register(struct target *target, enum gdb_regno regid,
static int dm013_select_hart(struct target *target, int hart_index);
static int riscv013_halt_prep(struct target *target);
static int riscv013_halt_go(struct target *target);
static int riscv013_halt_target(struct target *target);
static int riscv013_resume_go(struct target *target);
static int riscv013_step_current_hart(struct target *target);
static int riscv013_on_step(struct target *target);
@ -195,6 +197,7 @@ typedef struct {
uint8_t datasize;
uint8_t dataaccess;
int16_t dataaddr;
uint8_t nscratch;
/* The width of the hartsel field. */
unsigned hartsellen;
@ -1774,28 +1777,66 @@ static int set_dcsr_ebreak(struct target *target, bool step)
RISCV_INFO(r);
RISCV013_INFO(info);
riscv_reg_t original_dcsr, dcsr;
/* We want to twiddle some bits in the debug CSR so debugging works. */
if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
original_dcsr = dcsr;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
if (dcsr != original_dcsr &&
riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
return ERROR_FAIL;
if ((info->nscratch >= 1) && has_sufficient_progbuf(target, 8)) {
uint64_t set_ebreak_bits = 0;
uint64_t clr_ebreak_bits = 0;
if (r->riscv_ebreakm)
set_ebreak_bits |= CSR_DCSR_EBREAKM;
else
clr_ebreak_bits |= CSR_DCSR_EBREAKM;
if (r->riscv_ebreaks && riscv_supports_extension(target, 'S'))
set_ebreak_bits |= CSR_DCSR_EBREAKS;
else
clr_ebreak_bits |= CSR_DCSR_EBREAKS;
if (r->riscv_ebreaku && riscv_supports_extension(target, 'U'))
set_ebreak_bits |= CSR_DCSR_EBREAKU;
else
clr_ebreak_bits |= CSR_DCSR_EBREAKU;
if (r->riscv_ebreaku && riscv_supports_extension(target, 'H'))
set_ebreak_bits |= CSR_DCSR_EBREAKVS;
else
clr_ebreak_bits |= CSR_DCSR_EBREAKVS;
if (r->riscv_ebreaku && riscv_supports_extension(target, 'H'))
set_ebreak_bits |= CSR_DCSR_EBREAKVU;
else
clr_ebreak_bits |= CSR_DCSR_EBREAKVU;
struct riscv_program program;
riscv_program_init(&program, target);
riscv_program_insert(&program, csrw(S0, CSR_DSCRATCH0));
riscv_program_insert(&program, lui(S0, set_ebreak_bits));
riscv_program_insert(&program, csrrs(ZERO, S0, CSR_DCSR));
riscv_program_insert(&program, lui(S0, clr_ebreak_bits));
riscv_program_insert(&program, csrrc(ZERO, S0, CSR_DCSR));
if (step)
riscv_program_insert(&program, csrsi(CSR_DCSR, 0x4));
else
riscv_program_insert(&program, csrci(CSR_DCSR, 0x4));
riscv_program_insert(&program, csrr(S0, CSR_DSCRATCH0));
if (riscv_program_exec(&program, target) != ERROR_OK)
return ERROR_FAIL;
} else {
riscv_reg_t original_dcsr, dcsr;
/* We want to twiddle some bits in the debug CSR so debugging works. */
if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
original_dcsr = dcsr;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
if (dcsr != original_dcsr &&
riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
return ERROR_FAIL;
}
info->dcsr_ebreak_is_set = true;
return ERROR_OK;
}
static int halt_set_dcsr_ebreak(struct target *target)
{
RISCV_INFO(r);
RISCV013_INFO(info);
LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*");
/* Remove this hart from the halt group. This won't work on all targets
@ -1821,35 +1862,47 @@ static int halt_set_dcsr_ebreak(struct target *target)
*/
if (info->haltgroup_supported) {
bool supported;
if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK)
return ERROR_FAIL;
if (!supported)
LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. "
"Some harts may be unexpectedly halted.");
struct target_list *entry;
struct list_head *targets;
if (target->smp) {
targets = target->smp_targets;
foreach_smp_target(entry, targets) {
struct target *t = entry->target;
if (riscv013_halt_prep(t) != ERROR_OK) {
LOG_TARGET_INFO(target, "riscv013_halt_prep failed - t_coreid: %d", t->coreid);
return ERROR_FAIL;
}
}
}
int result = ERROR_OK;
int halt_result = ERROR_OK;
int resume_result = ERROR_OK;
r->prepped = true;
if (riscv013_halt_go(target) != ERROR_OK ||
set_dcsr_ebreak(target, false) != ERROR_OK ||
riscv013_step_or_resume_current_hart(target, false) != ERROR_OK) {
result = ERROR_FAIL;
halt_result = riscv013_halt_go(target);
if (halt_result == ERROR_OK) {
if (riscv013_on_step_or_resume(target, true, false) == ERROR_OK) {
resume_result = riscv013_step_or_resume_current_hart(target, false);
if (resume_result == ERROR_OK) {
target->state = TARGET_RUNNING;
target->debug_reason = DBG_REASON_NOTHALTED;
} else if (resume_result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
LOG_TARGET_INFO(target, "riscv013_resume_go aborted");
target->state = TARGET_UNAVAILABLE;
} else {
LOG_TARGET_INFO(target, "riscv013_resume_go failed");
result = ERROR_FAIL;
}
} else {
LOG_TARGET_INFO(target, "resume_prep failed");
result = ERROR_FAIL;
}
} else if (halt_result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
LOG_TARGET_INFO(target, "riscv013_halt_go aborted");
} else {
target->state = TARGET_RUNNING;
target->debug_reason = DBG_REASON_NOTHALTED;
}
/* Add it back to the halt group. */
if (info->haltgroup_supported) {
bool supported;
if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK)
return ERROR_FAIL;
if (!supported)
LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. "
"Some harts may be unexpectedly halted.", target->smp);
LOG_TARGET_INFO(target, "riscv013_halt_go failed");
result = ERROR_FAIL;
}
return result;
@ -1983,6 +2036,7 @@ static int examine(struct target *target)
info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE);
info->dataaccess = get_field(hartinfo, DM_HARTINFO_DATAACCESS);
info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR);
info->nscratch = get_field(hartinfo, DM_HARTINFO_NSCRATCH);
if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) {
LOG_TARGET_ERROR(target, "Debugger is not authenticated to target Debug Module. "
@ -2001,26 +2055,9 @@ static int examine(struct target *target)
info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT);
info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE);
LOG_TARGET_INFO(target, "datacount=%d progbufsize=%d",
info->datacount, info->progbufsize);
RISCV_INFO(r);
r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK);
if (!has_sufficient_progbuf(target, 2)) {
LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this "
"target. Memory may not always appear consistent. "
"(progbufsize=%d, impebreak=%d)", info->progbufsize,
r->impebreak);
}
if (info->progbufsize < 4 && riscv_enable_virtual) {
LOG_TARGET_ERROR(target, "set_enable_virtual is not available on this target. It "
"requires a program buffer size of at least 4. (progbufsize=%d) "
"Use `riscv set_enable_virtual off` to continue."
, info->progbufsize);
}
/* 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) {
@ -2056,16 +2093,41 @@ static int examine(struct target *target)
enum riscv_hart_state state_at_examine_start;
if (riscv_get_hart_state(target, &state_at_examine_start) != ERROR_OK)
return ERROR_FAIL;
/* Skip full examination and reporting of hart if it is currently unavailable */
const bool hart_unavailable_at_examine_start = state_at_examine_start == RISCV_STATE_UNAVAILABLE;
if (hart_unavailable_at_examine_start) {
LOG_TARGET_DEBUG(target, "Did not fully examine hart %d as it was currently unavailable, deferring examine.", info->index);
target->state = TARGET_UNAVAILABLE;
target->defer_examine = true;
return ERROR_OK;
}
const bool hart_halted_at_examine_start = state_at_examine_start == RISCV_STATE_HALTED;
if (!hart_halted_at_examine_start) {
r->prepped = true;
if (riscv013_halt_go(target) != ERROR_OK) {
if (riscv013_halt_target(target) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during %s",
info->index, __func__);
return ERROR_FAIL;
}
}
LOG_TARGET_INFO(target, "datacount=%d progbufsize=%d",
info->datacount, info->progbufsize);
if (!has_sufficient_progbuf(target, 2)) {
LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this "
"target. Memory may not always appear consistent. "
"(progbufsize=%d, impebreak=%d)", info->progbufsize,
r->impebreak);
}
if (info->progbufsize < 4 && riscv_enable_virtual) {
LOG_TARGET_ERROR(target, "set_enable_virtual is not available on this target. It "
"requires a program buffer size of at least 4. (progbufsize=%d) "
"Use `riscv set_enable_virtual off` to continue."
, info->progbufsize);
}
target->state = TARGET_HALTED;
target->debug_reason = hart_halted_at_examine_start ? DBG_REASON_UNDEFINED : DBG_REASON_DBGRQ;
@ -2691,7 +2753,7 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state
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!");
LOG_TARGET_DEBUG(target, "Hart unexpectedly reset!");
info->dcsr_ebreak_is_set = false;
/* TODO: Can we make this more obvious to eg. a gdb user? */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
@ -2726,6 +2788,29 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state
return ERROR_FAIL;
}
static int handle_became_available(struct target *target,
enum riscv_hart_state previous_riscv_state)
{
if (dm013_select_target(target) != ERROR_OK) {
LOG_TARGET_INFO(target, "dm013_select_target failed");
return ERROR_FAIL;
}
target->state = TARGET_HALTED;
int result = riscv013_step_or_resume_current_hart(target, false);
if (result == ERROR_OK) {
target->state = TARGET_RUNNING;
target->debug_reason = DBG_REASON_NOTHALTED;
} else if (result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
LOG_TARGET_INFO(target, "riscv013_step_or_resume_current_hart aborted");
target->state = TARGET_UNAVAILABLE;
return ERROR_OK;
} else {
LOG_TARGET_INFO(target, "riscv013_step_or_resume_current_hart failed");
return ERROR_FAIL;
}
return ERROR_OK;
}
static int handle_became_unavailable(struct target *target,
enum riscv_hart_state previous_riscv_state)
{
@ -2780,6 +2865,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->data_bits = &riscv013_data_bits;
generic_info->print_info = &riscv013_print_info;
generic_info->handle_became_available = &handle_became_available;
generic_info->handle_became_unavailable = &handle_became_unavailable;
generic_info->tick = &tick;
@ -2893,7 +2979,9 @@ static int deassert_reset(struct target *target)
info->dmi_busy_delay = orig_dmi_busy_delay;
if (target->reset_halt) {
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
target->state = TARGET_UNAVAILABLE;
} else if (target->reset_halt) {
target->state = TARGET_HALTED;
target->debug_reason = DBG_REASON_DBGRQ;
} else {
@ -4906,89 +4994,64 @@ static int dm013_select_hart(struct target *target, int hart_index)
return ERROR_OK;
}
/* 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)
{
RISCV_INFO(r);
dm013_info_t *dm = get_dm(target);
if (!dm)
return ERROR_FAIL;
if (!dm->hasel_supported) {
r->prepped = false;
return dm013_select_target(target);
}
assert(dm->hart_count);
unsigned hawindow_count = (dm->hart_count + 31) / 32;
uint32_t *hawindow = calloc(hawindow_count, sizeof(uint32_t));
if (!hawindow)
return ERROR_FAIL;
target_list_t *entry;
unsigned total_selected = 0;
unsigned int selected_index = 0;
list_for_each_entry(entry, &dm->target_list, list) {
struct target *t = entry->target;
struct riscv_info *info = riscv_info(t);
riscv013_info_t *info_013 = get_info(t);
unsigned int index = info_013->index;
LOG_TARGET_DEBUG(target, "index=%d, prepped=%d", index, info->prepped);
if (info->prepped) {
info_013->selected = true;
hawindow[index / 32] |= 1 << (index % 32);
info->prepped = false;
total_selected++;
selected_index = index;
}
}
if (total_selected == 0) {
LOG_TARGET_ERROR(target, "No harts were prepped!");
free(hawindow);
return ERROR_FAIL;
} else if (total_selected == 1) {
/* Don't use hasel if we only need to talk to one hart. */
free(hawindow);
return dm013_select_hart(target, selected_index);
}
if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK) {
free(hawindow);
return ERROR_FAIL;
}
for (unsigned i = 0; i < hawindow_count; i++) {
if (dm_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) {
free(hawindow);
return ERROR_FAIL;
}
if (dm_write(target, DM_HAWINDOW, hawindow[i]) != ERROR_OK) {
free(hawindow);
return ERROR_FAIL;
}
}
free(hawindow);
return ERROR_OK;
}
static int riscv013_halt_prep(struct target *target)
{
LOG_TARGET_DEBUG(target, "grouping hart");
if (target->smp) {
/* Let's make sure that all non-halted harts are in the same halt group */
riscv013_info_t *info = get_info(target);
if (info->haltgroup_supported) {
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
bool supported;
if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK)
return ERROR_FAIL;
if (!supported)
LOG_TARGET_ERROR(target, "Couldn't place hart %d in halt group %d. "
"Some harts may be unexpectedly halted.", target->coreid, target->smp);
}
}
return ERROR_OK;
}
static int riscv013_halt_go(struct target *target)
{
dm013_info_t *dm = get_dm(target);
if (!dm)
return ERROR_FAIL;
if (select_prepped_harts(target) != ERROR_OK)
return ERROR_FAIL;
LOG_TARGET_DEBUG(target, "halting hart");
if (dm013_select_target(target) != ERROR_OK) {
return ERROR_FAIL;
}
if (target->smp) {
/* Let's make sure that harts we want to halt are placed in another group */
riscv013_info_t *info = get_info(target);
if (info->haltgroup_supported) {
bool supported;
if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK)
return ERROR_FAIL;
if (!supported)
LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. "
"Some harts may be unexpectedly halted.");
}
}
int result = riscv013_halt_target(target);
if (result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
else if (result != ERROR_OK) {
return ERROR_FAIL;
}
return ERROR_OK;
}
static int riscv013_halt_target(struct target *target)
{
LOG_TARGET_DEBUG(target, "halting one hart");
dm013_info_t *dm = get_dm(target);
/* Issue the halt command, and then wait for the current hart to halt. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid);
@ -4997,13 +5060,12 @@ static int riscv013_halt_go(struct target *target)
for (size_t i = 0; i < 256; ++i) {
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
return ERROR_FAIL;
/* When no harts are running, there's no point in continuing this loop. */
/* When hart is not running, there's no point in continuing this loop. */
if (!get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))
break;
}
/* We declare success if no harts are running. One or more of them may be
* unavailable, though. */
/* We declare success if hart is not running. It may be unavailable, though. */
if ((get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))) {
if (dm_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK)
@ -5017,47 +5079,14 @@ static int riscv013_halt_go(struct target *target)
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0);
dm_write(target, DM_DMCONTROL, dmcontrol);
if (dm->current_hartid == HART_INDEX_MULTIPLE) {
target_list_t *entry;
list_for_each_entry(entry, &dm->target_list, list) {
struct target *t = entry->target;
uint32_t t_dmstatus;
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED) ||
get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
/* All harts are either halted or unavailable. No
* need to read dmstatus for each hart. */
t_dmstatus = dmstatus;
} else {
/* Only some harts were halted/unavailable. Read
* dmstatus for this one to see what its status
* is. */
riscv013_info_t *info = get_info(t);
dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
if (dm_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK)
return ERROR_FAIL;
dm->current_hartid = info->index;
if (dm_read(target, &t_dmstatus, DM_DMSTATUS) != ERROR_OK)
return ERROR_FAIL;
}
/* Set state for the current target based on its dmstatus. */
if (get_field(t_dmstatus, DM_DMSTATUS_ALLHALTED)) {
t->state = TARGET_HALTED;
if (t->debug_reason == DBG_REASON_NOTHALTED)
t->debug_reason = DBG_REASON_DBGRQ;
} else if (get_field(t_dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
t->state = TARGET_UNAVAILABLE;
}
}
} else {
/* Set state for the current target based on its dmstatus. */
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) {
target->state = TARGET_HALTED;
if (target->debug_reason == DBG_REASON_NOTHALTED)
target->debug_reason = DBG_REASON_DBGRQ;
} else if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
target->state = TARGET_UNAVAILABLE;
}
/* Set state for the current target based on its dmstatus. */
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) {
target->state = TARGET_HALTED;
if (target->debug_reason == DBG_REASON_NOTHALTED)
target->debug_reason = DBG_REASON_DBGRQ;
} else if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
target->state = TARGET_UNAVAILABLE;
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
return ERROR_OK;
@ -5065,9 +5094,6 @@ static int riscv013_halt_go(struct target *target)
static int riscv013_resume_go(struct target *target)
{
if (select_prepped_harts(target) != ERROR_OK)
return ERROR_FAIL;
return riscv013_step_or_resume_current_hart(target, false);
}
@ -5079,12 +5105,12 @@ static int riscv013_step_current_hart(struct target *target)
static int riscv013_resume_prep(struct target *target)
{
assert(target->state == TARGET_HALTED);
return riscv013_on_step_or_resume(target, false);
return riscv013_on_step_or_resume(target, false, false);
}
static int riscv013_on_step(struct target *target)
{
return riscv013_on_step_or_resume(target, true);
return riscv013_on_step_or_resume(target, false, true);
}
static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
@ -5220,17 +5246,17 @@ void riscv013_fill_dm_nop_u64(struct target *target, char *buf)
riscv013_fill_dmi_nop_u64(target, buf);
}
static int maybe_execute_fence_i(struct target *target)
static int maybe_execute_fence_i(struct target *target, bool skip)
{
if (has_sufficient_progbuf(target, 2))
if (!skip && has_sufficient_progbuf(target, 2))
return execute_fence(target);
return ERROR_OK;
}
/* Helper Functions. */
static int riscv013_on_step_or_resume(struct target *target, bool step)
static int riscv013_on_step_or_resume(struct target *target, bool skip, bool step)
{
if (maybe_execute_fence_i(target) != ERROR_OK)
if (maybe_execute_fence_i(target, skip) != ERROR_OK)
return ERROR_FAIL;
if (set_dcsr_ebreak(target, step) != ERROR_OK)
@ -5250,8 +5276,14 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
}
LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step);
if (riscv_flush_registers(target) != ERROR_OK)
if (riscv_flush_registers(target) != ERROR_OK) {
LOG_TARGET_INFO(target, "riscv_flush_registers failed");
return ERROR_FAIL;
}
if (dm013_select_target(target) != ERROR_OK) {
return ERROR_FAIL;
}
dm013_info_t *dm = get_dm(target);
/* Issue the resume command, and then wait for the current hart to resume. */
@ -5264,24 +5296,50 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
uint32_t dmstatus;
for (size_t i = 0; i < 256; ++i) {
usleep(10);
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
return ERROR_FAIL;
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL))
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) {
LOG_TARGET_INFO(target, "dmstatus_read failed");
return ERROR_FAIL;
}
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
LOG_TARGET_INFO(target, "dmstatus_read aborted");
target->state = TARGET_UNAVAILABLE;
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) {
dmcontrol = dmcontrol | DM_DMCONTROL_ACKHAVERESET;
}
if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0)
continue;
if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0)
continue;
dm_write(target, DM_DMCONTROL, dmcontrol);
if (target->smp) {
/* Let's make sure that this hart is placed back with all non-halted harts */
riscv013_info_t *info = get_info(target);
if (info->haltgroup_supported) {
bool supported;
if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK) {
LOG_TARGET_INFO(target, "set_group failed");
return ERROR_FAIL;
}
if (!supported)
LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. "
"Some harts may be unexpectedly halted.", target->smp);
}
}
return ERROR_OK;
}
dm_write(target, DM_DMCONTROL, dmcontrol);
LOG_TARGET_ERROR(target, "unable to resume");
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) {
LOG_TARGET_INFO(target, "dmstatus_read failed");
return ERROR_FAIL;
}
LOG_TARGET_ERROR(target, " dmstatus=0x%08x", dmstatus);
if (step) {
@ -5290,6 +5348,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
return ERROR_OK;
}
LOG_TARGET_INFO(target, "resume_current_hart failed");
return ERROR_FAIL;
}

View File

@ -534,6 +534,10 @@ static void riscv_deinit_target(struct target *target)
{
LOG_TARGET_DEBUG(target, "riscv_deinit_target()");
/* No need to deinit a target that has not been examined */
if (!target_was_examined(target))
return;
struct riscv_info *info = target->arch_info;
struct target_type *tt = get_target_type(target);
if (!tt)
@ -1920,28 +1924,31 @@ int riscv_halt(struct target *target)
LOG_TARGET_DEBUG(target, "halting all harts");
/* Only halt a hart if it has been examined (was available) */
int result = ERROR_OK;
if (target->smp) {
struct target_list *tlist;
foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
if (halt_prep(t) != ERROR_OK)
result = ERROR_FAIL;
if (target_was_examined(t))
if (halt_prep(t) != ERROR_OK)
result = ERROR_FAIL;
}
foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
struct riscv_info *i = riscv_info(t);
if (i->prepped) {
if (halt_go(t) != ERROR_OK)
result = ERROR_FAIL;
}
if (target_was_examined(t))
if (i->prepped)
if (halt_go(t) != ERROR_OK)
result = ERROR_FAIL;
}
foreach_smp_target(tlist, target->smp_targets) {
struct target *t = tlist->target;
if (halt_finish(t) != ERROR_OK)
return ERROR_FAIL;
if (target_was_examined(t))
if (halt_finish(t) != ERROR_OK)
return ERROR_FAIL;
}
} else {
@ -3039,11 +3046,21 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a
return ERROR_FAIL;
}
/* The hart apparently became unavailable while halted, so we want to resume it */
if (state == RISCV_STATE_HALTED && previous_riscv_state == RISCV_STATE_UNAVAILABLE) {
if (r->handle_became_available &&
r->handle_became_available(target, previous_riscv_state) != ERROR_OK)
return ERROR_FAIL;
if (riscv_get_hart_state(target, &state) != ERROR_OK)
return ERROR_FAIL;
}
if (target->state == TARGET_UNKNOWN || state != previous_riscv_state) {
switch (state) {
case RISCV_STATE_HALTED:
if (previous_riscv_state == RISCV_STATE_UNAVAILABLE)
if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) {
LOG_TARGET_INFO(target, "became available (halted)");
}
LOG_TARGET_DEBUG(target, " triggered a halt; previous_target_state=%d",
previous_target_state);
@ -3090,8 +3107,9 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a
break;
case RISCV_STATE_RUNNING:
if (previous_riscv_state == RISCV_STATE_UNAVAILABLE)
if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) {
LOG_TARGET_INFO(target, "became available (running)");
}
LOG_TARGET_DEBUG(target, " triggered running");
target->state = TARGET_RUNNING;
@ -3102,8 +3120,16 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a
break;
case RISCV_STATE_UNAVAILABLE:
LOG_TARGET_DEBUG(target, " became unavailable");
LOG_TARGET_INFO(target, "became unavailable.");
if (previous_riscv_state == RISCV_STATE_HALTED) {
LOG_TARGET_DEBUG(target, " became unavailable (halted)");
LOG_TARGET_INFO(target, "became unavailable (halted).");
} else if (previous_riscv_state == RISCV_STATE_RUNNING) {
LOG_TARGET_DEBUG(target, " became unavailable (running)");
LOG_TARGET_INFO(target, "became unavailable (running).");
} else {
LOG_TARGET_DEBUG(target, " became unavailable");
LOG_TARGET_INFO(target, "became unavailable.");
}
target->state = TARGET_UNAVAILABLE;
if (r->handle_became_unavailable &&
r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK)
@ -3206,8 +3232,10 @@ int riscv_openocd_poll(struct target *target)
continue;
enum riscv_next_action next_action;
if (riscv_poll_hart(t, &next_action) != ERROR_OK)
if (riscv_poll_hart(t, &next_action) != ERROR_OK) {
LOG_TARGET_INFO(target, "riscv_poll_hart failed - next_action: %d", next_action);
return ERROR_FAIL;
}
switch (next_action) {
case RPH_NONE:
@ -3264,8 +3292,10 @@ int riscv_openocd_poll(struct target *target)
foreach_smp_target(entry, targets) {
struct target *t = entry->target;
struct riscv_info *info = riscv_info(t);
if (info->tick && info->tick(t) != ERROR_OK)
if (info->tick && info->tick(t) != ERROR_OK) {
LOG_TARGET_INFO(target, "info_tick failed - t_coreid: %d", t->coreid);
return ERROR_FAIL;
}
}
/* Sample memory if any target is running. */

View File

@ -213,6 +213,8 @@ struct riscv_info {
enum riscv_hart_state previous_riscv_state);
int (*handle_became_running)(struct target *target,
enum riscv_hart_state previous_riscv_state);
int (*handle_became_available)(struct target *target,
enum riscv_hart_state previous_riscv_state);
int (*handle_became_unavailable)(struct target *target,
enum riscv_hart_state previous_riscv_state);

View File

@ -131,6 +131,11 @@ proc ocd_process_reset_inner { MODE } {
}
}
# no need to wait for a target that is unavailable anyway
if { [$t curstate] == "unavailable" } {
continue
}
# Wait up to 1 second for target to halt. Why 1sec? Cause
# the JTAG tap reset signal might be hooked to a slow
# resistor/capacitor circuit - and it might take a while
@ -142,8 +147,11 @@ proc ocd_process_reset_inner { MODE } {
# Did we succeed?
set s [$t curstate]
if { $s == "unavailable" } {
continue
}
if { $s != "halted" } {
return -code error [format "TARGET: %s - Not halted" $t]
return -code error [format "TARGET: %s - Not halted (%s)" $t $s]
}
}
}
@ -160,6 +168,9 @@ proc ocd_process_reset_inner { MODE } {
if { ![$t was_examined] && [$t examine_deferred] } {
continue
}
if { [$t curstate] == "unavailable" } {
continue
}
set err [catch "$t arp_waitstate halted 5000"]
# Did it halt?

View File

@ -486,8 +486,10 @@ int target_poll(struct target *target)
}
retval = target->type->poll(target);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
LOG_TARGET_INFO(target, "target->type->poll failed");
return retval;
}
if (target->halt_issued) {
if (target->state == TARGET_HALTED)
@ -676,6 +678,7 @@ int target_examine_one(struct target *target)
target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
bool defer_state = target->defer_examine;
int retval = target->type->examine(target);
if (retval != ERROR_OK) {
LOG_TARGET_ERROR(target, "Examination failed");
@ -685,11 +688,17 @@ int target_examine_one(struct target *target)
return retval;
}
LOG_USER("[%s] Target successfully examined.", target_name(target));
target_set_examined(target);
if (target->defer_examine) {
LOG_USER("[%s] Target currently unavailable for full examination.", target_name(target));
target->defer_examine = defer_state;
target_reset_examined(target);
} else {
LOG_USER("[%s] Target successfully examined.", target_name(target));
target_set_examined(target);
}
target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
LOG_TARGET_INFO(target, "Examination succeed");
LOG_TARGET_DEBUG(target, "Examination succeed");
return ERROR_OK;
}
@ -5261,13 +5270,19 @@ COMMAND_HANDLER(handle_target_examine)
return ERROR_OK;
}
bool defer_state = target->defer_examine;
int retval = target->type->examine(target);
if (retval != ERROR_OK) {
target_reset_examined(target);
return retval;
}
target_set_examined(target);
if (target->defer_examine) {
LOG_INFO("Unable to do full examination of %s", target_name(target));
target->defer_examine = defer_state;
target_reset_examined(target);
} else
target_set_examined(target);
return ERROR_OK;
}