aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcgsfv <cgsfv@users.noreply.github.com>2024-05-08 16:07:16 -0700
committercgsfv <cgsfv@users.noreply.github.com>2024-05-08 16:07:56 -0700
commitea57d2ae2765d53898135fbfa927cfc5d68d3c13 (patch)
treec677bad537d46ce44e1f15492c768cb11e6c7474
parentae7ffa424e1b686559ae833ce2d384ded47ba4c4 (diff)
downloadriscv-openocd-examine_unavailable_harts_rebase.zip
riscv-openocd-examine_unavailable_harts_rebase.tar.gz
riscv-openocd-examine_unavailable_harts_rebase.tar.bz2
Improved handling of unavailable coresexamine_unavailable_harts_rebase
-rw-r--r--src/target/riscv/opcodes.h12
-rw-r--r--src/target/riscv/riscv-013.c398
-rw-r--r--src/target/riscv/riscv.c44
-rw-r--r--src/target/riscv/riscv.h2
-rw-r--r--src/target/startup.tcl13
-rw-r--r--src/target/target.c21
6 files changed, 292 insertions, 198 deletions
diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h
index 59c3413..70fca25 100644
--- a/src/target/riscv/opcodes.h
+++ b/src/target/riscv/opcodes.h
@@ -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)
{
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 71cfcd6..1940647 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -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);
@@ -203,6 +205,7 @@ typedef struct {
uint8_t datasize;
uint8_t dataaccess;
int16_t dataaddr;
+ uint8_t nscratch;
/* DM that provides access to this target. */
dm013_info_t *dm;
@@ -1826,28 +1829,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
@@ -1873,36 +1914,37 @@ 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)
+ return ERROR_FAIL;
+ }
}
int 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) {
+ int halt_result = ERROR_OK;
+ int resume_result = ERROR_OK;
+
+ 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)
+ target->state = TARGET_UNAVAILABLE;
+ else
+ result = ERROR_FAIL;
+ } else
+ result = ERROR_FAIL;
+ else if (halt_result != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
result = ERROR_FAIL;
- } 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);
- }
return result;
}
@@ -2150,6 +2192,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. "
@@ -2168,42 +2211,50 @@ 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);
- }
-
/* Don't call any riscv_* functions until after we've counted the number of
* cores and initialized registers. */
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;
@@ -2827,7 +2878,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 |
@@ -2868,6 +2919,24 @@ 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)
+ 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;
+ return ERROR_OK;
+ } else if (result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+ target->state = TARGET_UNAVAILABLE;
+ return ERROR_OK;
+ }
+ return ERROR_FAIL;
+}
+
static int handle_became_unavailable(struct target *target,
enum riscv_hart_state previous_riscv_state)
{
@@ -2922,6 +2991,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;
@@ -3060,7 +3130,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 {
@@ -5094,94 +5166,67 @@ 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)
+static int riscv013_halt_prep(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;
+ 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);
}
}
- 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);
- }
+ return ERROR_OK;
+}
- if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK) {
- free(hawindow);
+static int riscv013_halt_go(struct target *target)
+{
+ LOG_TARGET_DEBUG(target, "halting hart");
+
+ if (dm013_select_target(target) != ERROR_OK) {
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;
+ 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.");
}
}
- free(hawindow);
- return ERROR_OK;
-}
+ 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;
-static int riscv013_halt_prep(struct target *target)
-{
return ERROR_OK;
}
-static int riscv013_halt_go(struct target *target)
+static int riscv013_halt_target(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");
+ LOG_TARGET_DEBUG(target, "halting one hart");
/* `haltreq` should not be issued if `abstractcs.busy` is set. */
int result = wait_for_idle_if_needed(target);
if (result != ERROR_OK)
return result;
+ 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);
@@ -5190,13 +5235,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)
@@ -5210,44 +5254,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. */
- if (dm013_select_target(target) != ERROR_OK)
- return ERROR_FAIL;
- 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;
@@ -5255,9 +5269,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);
}
@@ -5269,12 +5280,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)
@@ -5410,17 +5421,17 @@ void riscv013_fill_dm_nop(struct target *target, char *buf)
riscv013_fill_dmi_nop(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)
@@ -5443,6 +5454,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
if (riscv_flush_registers(target) != ERROR_OK)
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. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
@@ -5460,14 +5474,32 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
usleep(10);
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
return ERROR_FAIL;
- if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL))
- return ERROR_FAIL;
+ if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
+ 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)
+ 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;
}
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index d610b33..10c6ad8 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -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)
@@ -1950,28 +1954,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 {
@@ -3070,6 +3077,15 @@ 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:
@@ -3133,8 +3149,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)
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index 7a95af6..fa2c0dc 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -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);
diff --git a/src/target/startup.tcl b/src/target/startup.tcl
index 75e0edc..8ddac0c 100644
--- a/src/target/startup.tcl
+++ b/src/target/startup.tcl
@@ -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?
diff --git a/src/target/target.c b/src/target/target.c
index 0c57292..0d82090 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -676,6 +676,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 +686,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 +5268,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;
}