Compare commits
2 Commits
riscv
...
examine_un
Author | SHA1 | Date |
---|---|---|
|
a4a158dc54 | |
|
ea57d2ae27 |
|
@ -71,6 +71,12 @@ static uint32_t jal(unsigned int rd, uint32_t imm)
|
||||||
return imm_j(imm) | inst_rd(rd) | MATCH_JAL;
|
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) __attribute__ ((unused));
|
||||||
static uint32_t csrsi(unsigned int csr, uint16_t imm)
|
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;
|
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) __attribute__ ((unused));
|
||||||
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
|
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "target/target.h"
|
#include "target/target.h"
|
||||||
#include "target/algorithm.h"
|
#include "target/algorithm.h"
|
||||||
#include "target/target_type.h"
|
#include "target/target_type.h"
|
||||||
|
#include <target/smp.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
#include "jtag/jtag.h"
|
#include "jtag/jtag.h"
|
||||||
#include "target/register.h"
|
#include "target/register.h"
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
#include "debug_reg_printer.h"
|
#include "debug_reg_printer.h"
|
||||||
#include "field_helpers.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,
|
static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||||
bool step);
|
bool step);
|
||||||
static int riscv013_clear_abstract_error(struct target *target);
|
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 dm013_select_hart(struct target *target, int hart_index);
|
||||||
static int riscv013_halt_prep(struct target *target);
|
static int riscv013_halt_prep(struct target *target);
|
||||||
static int riscv013_halt_go(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_resume_go(struct target *target);
|
||||||
static int riscv013_step_current_hart(struct target *target);
|
static int riscv013_step_current_hart(struct target *target);
|
||||||
static int riscv013_on_step(struct target *target);
|
static int riscv013_on_step(struct target *target);
|
||||||
|
@ -203,6 +205,7 @@ typedef struct {
|
||||||
uint8_t datasize;
|
uint8_t datasize;
|
||||||
uint8_t dataaccess;
|
uint8_t dataaccess;
|
||||||
int16_t dataaddr;
|
int16_t dataaddr;
|
||||||
|
uint8_t nscratch;
|
||||||
|
|
||||||
/* DM that provides access to this target. */
|
/* DM that provides access to this target. */
|
||||||
dm013_info_t *dm;
|
dm013_info_t *dm;
|
||||||
|
@ -1826,28 +1829,66 @@ static int set_dcsr_ebreak(struct target *target, bool step)
|
||||||
|
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
riscv_reg_t original_dcsr, dcsr;
|
|
||||||
/* We want to twiddle some bits in the debug CSR so debugging works. */
|
if ((info->nscratch >= 1) && has_sufficient_progbuf(target, 8)) {
|
||||||
if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
|
uint64_t set_ebreak_bits = 0;
|
||||||
return ERROR_FAIL;
|
uint64_t clr_ebreak_bits = 0;
|
||||||
original_dcsr = dcsr;
|
if (r->riscv_ebreakm)
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
|
set_ebreak_bits |= CSR_DCSR_EBREAKM;
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm);
|
else
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S'));
|
clr_ebreak_bits |= CSR_DCSR_EBREAKM;
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U'));
|
if (r->riscv_ebreaks && riscv_supports_extension(target, 'S'))
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
|
set_ebreak_bits |= CSR_DCSR_EBREAKS;
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
|
else
|
||||||
if (dcsr != original_dcsr &&
|
clr_ebreak_bits |= CSR_DCSR_EBREAKS;
|
||||||
riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
|
if (r->riscv_ebreaku && riscv_supports_extension(target, 'U'))
|
||||||
return ERROR_FAIL;
|
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;
|
info->dcsr_ebreak_is_set = true;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int halt_set_dcsr_ebreak(struct target *target)
|
static int halt_set_dcsr_ebreak(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
|
||||||
RISCV013_INFO(info);
|
|
||||||
LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*");
|
LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*");
|
||||||
|
|
||||||
/* Remove this hart from the halt group. This won't work on all targets
|
/* 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) {
|
struct target_list *entry;
|
||||||
bool supported;
|
struct list_head *targets;
|
||||||
if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
if (target->smp) {
|
||||||
if (!supported)
|
targets = target->smp_targets;
|
||||||
LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. "
|
foreach_smp_target(entry, targets) {
|
||||||
"Some harts may be unexpectedly halted.");
|
struct target *t = entry->target;
|
||||||
|
if (riscv013_halt_prep(t) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = ERROR_OK;
|
int result = ERROR_OK;
|
||||||
|
int halt_result = ERROR_OK;
|
||||||
|
int resume_result = ERROR_OK;
|
||||||
|
|
||||||
r->prepped = true;
|
halt_result = riscv013_halt_go(target);
|
||||||
if (riscv013_halt_go(target) != ERROR_OK ||
|
if (halt_result == ERROR_OK)
|
||||||
set_dcsr_ebreak(target, false) != ERROR_OK ||
|
if (riscv013_on_step_or_resume(target, true, false) == ERROR_OK) {
|
||||||
riscv013_step_or_resume_current_hart(target, 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;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2150,6 +2192,7 @@ static int examine(struct target *target)
|
||||||
info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE);
|
info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE);
|
||||||
info->dataaccess = get_field(hartinfo, DM_HARTINFO_DATAACCESS);
|
info->dataaccess = get_field(hartinfo, DM_HARTINFO_DATAACCESS);
|
||||||
info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR);
|
info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR);
|
||||||
|
info->nscratch = get_field(hartinfo, DM_HARTINFO_NSCRATCH);
|
||||||
|
|
||||||
if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) {
|
if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) {
|
||||||
LOG_TARGET_ERROR(target, "Debugger is not authenticated to target Debug Module. "
|
LOG_TARGET_ERROR(target, "Debugger is not authenticated to target Debug Module. "
|
||||||
|
@ -2168,12 +2211,36 @@ static int examine(struct target *target)
|
||||||
info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT);
|
info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT);
|
||||||
info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE);
|
info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE);
|
||||||
|
|
||||||
LOG_TARGET_INFO(target, "datacount=%d progbufsize=%d",
|
|
||||||
info->datacount, info->progbufsize);
|
|
||||||
|
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK);
|
r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK);
|
||||||
|
|
||||||
|
/* Don't call any riscv_* functions until after we've counted the number of
|
||||||
|
* cores and initialized registers. */
|
||||||
|
|
||||||
|
enum riscv_hart_state riscv_state_at_examine_start;
|
||||||
|
if (riscv_get_hart_state(target, &riscv_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 = riscv_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 = riscv_state_at_examine_start == RISCV_STATE_HALTED;
|
||||||
|
if (!hart_halted_at_examine_start) {
|
||||||
|
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)) {
|
if (!has_sufficient_progbuf(target, 2)) {
|
||||||
LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this "
|
LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this "
|
||||||
"target. Memory may not always appear consistent. "
|
"target. Memory may not always appear consistent. "
|
||||||
|
@ -2188,22 +2255,6 @@ static int examine(struct target *target)
|
||||||
, info->progbufsize);
|
, 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;
|
|
||||||
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) {
|
|
||||||
LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during %s",
|
|
||||||
info->index, __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
target->debug_reason = hart_halted_at_examine_start ? DBG_REASON_UNDEFINED : DBG_REASON_DBGRQ;
|
target->debug_reason = hart_halted_at_examine_start ? DBG_REASON_UNDEFINED : DBG_REASON_DBGRQ;
|
||||||
|
|
||||||
|
@ -2279,11 +2330,11 @@ static int examine(struct target *target)
|
||||||
if (set_dcsr_ebreak(target, false) != ERROR_OK)
|
if (set_dcsr_ebreak(target, false) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (state_at_examine_start == RISCV_STATE_RUNNING) {
|
if (riscv_state_at_examine_start == RISCV_STATE_RUNNING) {
|
||||||
riscv013_step_or_resume_current_hart(target, false);
|
riscv013_step_or_resume_current_hart(target, false);
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
target->debug_reason = DBG_REASON_NOTHALTED;
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
} else if (state_at_examine_start == RISCV_STATE_HALTED) {
|
} else if (riscv_state_at_examine_start == RISCV_STATE_HALTED) {
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
target->debug_reason = DBG_REASON_UNDEFINED;
|
target->debug_reason = DBG_REASON_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
@ -2817,7 +2868,7 @@ static int sample_memory(struct target *target,
|
||||||
return sample_memory_bus_v1(target, buf, config, until_ms);
|
return sample_memory_bus_v1(target, buf, config, until_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state *riscv_state)
|
||||||
{
|
{
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
if (dm013_select_target(target) != ERROR_OK)
|
if (dm013_select_target(target) != ERROR_OK)
|
||||||
|
@ -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)
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) {
|
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;
|
info->dcsr_ebreak_is_set = false;
|
||||||
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
|
||||||
|
@ -2849,25 +2900,43 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state
|
||||||
dm_write(target, DM_DMCONTROL, dmcontrol);
|
dm_write(target, DM_DMCONTROL, dmcontrol);
|
||||||
}
|
}
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLNONEXISTENT)) {
|
if (get_field(dmstatus, DM_DMSTATUS_ALLNONEXISTENT)) {
|
||||||
*state = RISCV_STATE_NON_EXISTENT;
|
*riscv_state = RISCV_STATE_NON_EXISTENT;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
|
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
|
||||||
*state = RISCV_STATE_UNAVAILABLE;
|
*riscv_state = RISCV_STATE_UNAVAILABLE;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) {
|
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) {
|
||||||
*state = RISCV_STATE_HALTED;
|
*riscv_state = RISCV_STATE_HALTED;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) {
|
if (get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) {
|
||||||
*state = RISCV_STATE_RUNNING;
|
*riscv_state = RISCV_STATE_RUNNING;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
LOG_TARGET_ERROR(target, "Couldn't determine state. dmstatus=0x%x", dmstatus);
|
LOG_TARGET_ERROR(target, "Couldn't determine state. dmstatus=0x%x", dmstatus);
|
||||||
return ERROR_FAIL;
|
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,
|
static int handle_became_unavailable(struct target *target,
|
||||||
enum riscv_hart_state previous_riscv_state)
|
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->data_bits = &riscv013_data_bits;
|
||||||
generic_info->print_info = &riscv013_print_info;
|
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->handle_became_unavailable = &handle_became_unavailable;
|
||||||
generic_info->tick = &tick;
|
generic_info->tick = &tick;
|
||||||
|
|
||||||
|
@ -3060,7 +3130,9 @@ static int deassert_reset(struct target *target)
|
||||||
|
|
||||||
info->dmi_busy_delay = orig_dmi_busy_delay;
|
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->state = TARGET_HALTED;
|
||||||
target->debug_reason = DBG_REASON_DBGRQ;
|
target->debug_reason = DBG_REASON_DBGRQ;
|
||||||
} else {
|
} else {
|
||||||
|
@ -5094,94 +5166,67 @@ static int dm013_select_hart(struct target *target, int hart_index)
|
||||||
return ERROR_OK;
|
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)
|
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;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_halt_go(struct target *target)
|
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");
|
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");
|
||||||
|
|
||||||
/* `haltreq` should not be issued if `abstractcs.busy` is set. */
|
/* `haltreq` should not be issued if `abstractcs.busy` is set. */
|
||||||
int result = wait_for_idle_if_needed(target);
|
int result = wait_for_idle_if_needed(target);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
dm013_info_t *dm = get_dm(target);
|
||||||
/* Issue the halt command, and then wait for the current hart to halt. */
|
/* Issue the halt command, and then wait for the current hart to halt. */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
|
||||||
dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid);
|
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) {
|
for (size_t i = 0; i < 256; ++i) {
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
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))
|
if (!get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We declare success if no harts are running. One or more of them may be
|
/* We declare success if hart is not running. It may be unavailable, though. */
|
||||||
* unavailable, though. */
|
|
||||||
|
|
||||||
if ((get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))) {
|
if ((get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))) {
|
||||||
if (dm_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK)
|
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);
|
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0);
|
||||||
dm_write(target, DM_DMCONTROL, dmcontrol);
|
dm_write(target, DM_DMCONTROL, dmcontrol);
|
||||||
|
|
||||||
if (dm->current_hartid == HART_INDEX_MULTIPLE) {
|
/* Set state for the current target based on its dmstatus. */
|
||||||
target_list_t *entry;
|
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) {
|
||||||
list_for_each_entry(entry, &dm->target_list, list) {
|
target->state = TARGET_HALTED;
|
||||||
struct target *t = entry->target;
|
if (target->debug_reason == DBG_REASON_NOTHALTED)
|
||||||
uint32_t t_dmstatus;
|
target->debug_reason = DBG_REASON_DBGRQ;
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED) ||
|
} else if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
|
||||||
get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
|
target->state = TARGET_UNAVAILABLE;
|
||||||
/* All harts are either halted or unavailable. No
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -5255,9 +5269,6 @@ static int riscv013_halt_go(struct target *target)
|
||||||
|
|
||||||
static int riscv013_resume_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);
|
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)
|
static int riscv013_resume_prep(struct target *target)
|
||||||
{
|
{
|
||||||
assert(target->state == TARGET_HALTED);
|
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)
|
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)
|
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);
|
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 execute_fence(target);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper Functions. */
|
/* 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;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (set_dcsr_ebreak(target, step) != ERROR_OK)
|
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)
|
if (riscv_flush_registers(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
if (dm013_select_target(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
dm013_info_t *dm = get_dm(target);
|
dm013_info_t *dm = get_dm(target);
|
||||||
/* Issue the resume command, and then wait for the current hart to resume. */
|
/* Issue the resume command, and then wait for the current hart to resume. */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
|
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);
|
usleep(10);
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL))
|
if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) {
|
||||||
return ERROR_FAIL;
|
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)
|
if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0)
|
||||||
continue;
|
continue;
|
||||||
if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0)
|
if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dm_write(target, DM_DMCONTROL, dmcontrol);
|
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;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -534,6 +534,10 @@ static void riscv_deinit_target(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_TARGET_DEBUG(target, "riscv_deinit_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 riscv_info *info = target->arch_info;
|
||||||
struct target_type *tt = get_target_type(target);
|
struct target_type *tt = get_target_type(target);
|
||||||
if (!tt)
|
if (!tt)
|
||||||
|
@ -1893,10 +1897,10 @@ static int riscv_halt_go_all_harts(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
||||||
enum riscv_hart_state state;
|
enum riscv_hart_state riscv_state;
|
||||||
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
if (riscv_get_hart_state(target, &riscv_state) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (state == RISCV_STATE_HALTED) {
|
if (riscv_state == RISCV_STATE_HALTED) {
|
||||||
LOG_TARGET_DEBUG(target, "Hart is already halted.");
|
LOG_TARGET_DEBUG(target, "Hart is already halted.");
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
|
@ -1950,28 +1954,31 @@ int riscv_halt(struct target *target)
|
||||||
|
|
||||||
LOG_TARGET_DEBUG(target, "halting all harts");
|
LOG_TARGET_DEBUG(target, "halting all harts");
|
||||||
|
|
||||||
|
/* Only halt a hart if it has been examined (was available) */
|
||||||
int result = ERROR_OK;
|
int result = ERROR_OK;
|
||||||
if (target->smp) {
|
if (target->smp) {
|
||||||
struct target_list *tlist;
|
struct target_list *tlist;
|
||||||
foreach_smp_target(tlist, target->smp_targets) {
|
foreach_smp_target(tlist, target->smp_targets) {
|
||||||
struct target *t = tlist->target;
|
struct target *t = tlist->target;
|
||||||
if (halt_prep(t) != ERROR_OK)
|
if (target_was_examined(t))
|
||||||
result = ERROR_FAIL;
|
if (halt_prep(t) != ERROR_OK)
|
||||||
|
result = ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach_smp_target(tlist, target->smp_targets) {
|
foreach_smp_target(tlist, target->smp_targets) {
|
||||||
struct target *t = tlist->target;
|
struct target *t = tlist->target;
|
||||||
struct riscv_info *i = riscv_info(t);
|
struct riscv_info *i = riscv_info(t);
|
||||||
if (i->prepped) {
|
if (target_was_examined(t))
|
||||||
if (halt_go(t) != ERROR_OK)
|
if (i->prepped)
|
||||||
result = ERROR_FAIL;
|
if (halt_go(t) != ERROR_OK)
|
||||||
}
|
result = ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach_smp_target(tlist, target->smp_targets) {
|
foreach_smp_target(tlist, target->smp_targets) {
|
||||||
struct target *t = tlist->target;
|
struct target *t = tlist->target;
|
||||||
if (halt_finish(t) != ERROR_OK)
|
if (target_was_examined(t))
|
||||||
return ERROR_FAIL;
|
if (halt_finish(t) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -3054,24 +3061,33 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a
|
||||||
|
|
||||||
/* If OpenOCD thinks we're running but this hart is halted then it's time
|
/* If OpenOCD thinks we're running but this hart is halted then it's time
|
||||||
* to raise an event. */
|
* to raise an event. */
|
||||||
enum riscv_hart_state state;
|
enum riscv_hart_state riscv_state;
|
||||||
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
if (riscv_get_hart_state(target, &riscv_state) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (state == RISCV_STATE_NON_EXISTENT) {
|
if (riscv_state == RISCV_STATE_NON_EXISTENT) {
|
||||||
LOG_TARGET_ERROR(target, "Hart is non-existent!");
|
LOG_TARGET_ERROR(target, "Hart is non-existent!");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) {
|
if (riscv_state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) {
|
||||||
/* If we've been idle for a while, flush the register cache. Just in case
|
/* If we've been idle for a while, flush the register cache. Just in case
|
||||||
* OpenOCD is going to be disconnected without shutting down cleanly. */
|
* OpenOCD is going to be disconnected without shutting down cleanly. */
|
||||||
if (riscv_flush_registers(target) != ERROR_OK)
|
if (riscv_flush_registers(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->state == TARGET_UNKNOWN || state != previous_riscv_state) {
|
/* The hart apparently became unavailable while halted, so we want to resume it */
|
||||||
switch (state) {
|
// if (riscv_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, &riscv_state) != ERROR_OK)
|
||||||
|
// return ERROR_FAIL;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (target->state == TARGET_UNKNOWN || riscv_state != previous_riscv_state) {
|
||||||
|
switch (riscv_state) {
|
||||||
case RISCV_STATE_HALTED:
|
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_INFO(target, "became available (halted)");
|
||||||
|
@ -3133,8 +3149,16 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RISCV_STATE_UNAVAILABLE:
|
case RISCV_STATE_UNAVAILABLE:
|
||||||
LOG_TARGET_DEBUG(target, " became unavailable");
|
if (previous_riscv_state == RISCV_STATE_HALTED) {
|
||||||
LOG_TARGET_INFO(target, "became unavailable.");
|
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;
|
target->state = TARGET_UNAVAILABLE;
|
||||||
if (r->handle_became_unavailable &&
|
if (r->handle_became_unavailable &&
|
||||||
r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK)
|
r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK)
|
||||||
|
@ -5337,11 +5361,11 @@ int riscv_save_register(struct target *target, enum gdb_regno regid)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *riscv_state)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
assert(r->get_hart_state);
|
assert(r->get_hart_state);
|
||||||
return r->get_hart_state(target, state);
|
return r->get_hart_state(target, riscv_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum riscv_halt_reason riscv_halt_reason(struct target *target)
|
static enum riscv_halt_reason riscv_halt_reason(struct target *target)
|
||||||
|
|
|
@ -199,7 +199,7 @@ struct riscv_info {
|
||||||
int (*set_register_buf)(struct target *target, enum gdb_regno regno,
|
int (*set_register_buf)(struct target *target, enum gdb_regno regno,
|
||||||
const uint8_t *buf);
|
const uint8_t *buf);
|
||||||
int (*select_target)(struct target *target);
|
int (*select_target)(struct target *target);
|
||||||
int (*get_hart_state)(struct target *target, enum riscv_hart_state *state);
|
int (*get_hart_state)(struct target *target, enum riscv_hart_state *riscv_state);
|
||||||
/* Resume this target, as well as every other prepped target that can be
|
/* Resume this target, as well as every other prepped target that can be
|
||||||
* resumed near-simultaneously. Clear the prepped flag on any target that
|
* resumed near-simultaneously. Clear the prepped flag on any target that
|
||||||
* was resumed. */
|
* was resumed. */
|
||||||
|
@ -213,6 +213,8 @@ struct riscv_info {
|
||||||
enum riscv_hart_state previous_riscv_state);
|
enum riscv_hart_state previous_riscv_state);
|
||||||
int (*handle_became_running)(struct target *target,
|
int (*handle_became_running)(struct target *target,
|
||||||
enum riscv_hart_state previous_riscv_state);
|
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,
|
int (*handle_became_unavailable)(struct target *target,
|
||||||
enum riscv_hart_state previous_riscv_state);
|
enum riscv_hart_state previous_riscv_state);
|
||||||
|
|
||||||
|
@ -425,7 +427,7 @@ int riscv_flush_registers(struct target *target);
|
||||||
|
|
||||||
/* Checks the state of the current hart -- "is_halted" checks the actual
|
/* Checks the state of the current hart -- "is_halted" checks the actual
|
||||||
* on-device register. */
|
* on-device register. */
|
||||||
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state);
|
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *riscv_state);
|
||||||
|
|
||||||
/* These helper functions let the generic program interface get target-specific
|
/* These helper functions let the generic program interface get target-specific
|
||||||
* information. */
|
* information. */
|
||||||
|
|
|
@ -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
|
# Wait up to 1 second for target to halt. Why 1sec? Cause
|
||||||
# the JTAG tap reset signal might be hooked to a slow
|
# the JTAG tap reset signal might be hooked to a slow
|
||||||
# resistor/capacitor circuit - and it might take a while
|
# resistor/capacitor circuit - and it might take a while
|
||||||
|
@ -142,8 +147,11 @@ proc ocd_process_reset_inner { MODE } {
|
||||||
# Did we succeed?
|
# Did we succeed?
|
||||||
set s [$t curstate]
|
set s [$t curstate]
|
||||||
|
|
||||||
|
if { $s == "unavailable" } {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if { $s != "halted" } {
|
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] } {
|
if { ![$t was_examined] && [$t examine_deferred] } {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if { [$t curstate] == "unavailable" } {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
set err [catch "$t arp_waitstate halted 5000"]
|
set err [catch "$t arp_waitstate halted 5000"]
|
||||||
# Did it halt?
|
# Did it halt?
|
||||||
|
|
|
@ -676,6 +676,7 @@ int target_examine_one(struct target *target)
|
||||||
|
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
|
target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
|
||||||
|
|
||||||
|
bool defer_state = target->defer_examine;
|
||||||
int retval = target->type->examine(target);
|
int retval = target->type->examine(target);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_TARGET_ERROR(target, "Examination failed");
|
LOG_TARGET_ERROR(target, "Examination failed");
|
||||||
|
@ -685,11 +686,17 @@ int target_examine_one(struct target *target)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_USER("[%s] Target successfully examined.", target_name(target));
|
if (target->defer_examine) {
|
||||||
target_set_examined(target);
|
LOG_TARGET_DEBUG(target, "Currently unavailable for full examination");
|
||||||
|
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);
|
target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
|
||||||
|
|
||||||
LOG_TARGET_INFO(target, "Examination succeed");
|
LOG_TARGET_DEBUG(target, "Examination succeed");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5261,13 +5268,19 @@ COMMAND_HANDLER(handle_target_examine)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool defer_state = target->defer_examine;
|
||||||
int retval = target->type->examine(target);
|
int retval = target->type->examine(target);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
target_reset_examined(target);
|
target_reset_examined(target);
|
||||||
return retval;
|
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;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue