diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 142b5f705..e5edfef24 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1343,6 +1343,11 @@ static int examine(struct target *target) break; r->hart_count = i + 1; + if (!riscv_havereset_not_supported && + get_field(s, DMI_DMSTATUS_ANYHAVERESET)) + dmi_write(target, DMI_DMCONTROL, + DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET); + if (!riscv_is_halted(target)) { if (riscv013_halt_current_hart(target) != ERROR_OK) { LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i); @@ -1350,14 +1355,6 @@ static int examine(struct target *target) } } - /* TODO: We read dmstatus above, then in is_halted, then several times - * in halt_current_hart, and then again here. */ - if (dmstatus_read(target, &s, true) != ERROR_OK) - return ERROR_FAIL; - if (get_field(s, DMI_DMSTATUS_ANYHAVERESET)) - dmi_write(target, DMI_DMCONTROL, - DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET); - /* Without knowing anything else we can at least mess with the * program buffer. */ r->debug_buffer_size[i] = info->progbufsize; @@ -1569,8 +1566,6 @@ static int deassert_reset(struct target *target) RISCV013_INFO(info); select_dmi(target); - LOG_DEBUG("%d", r->current_hartid); - /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0; control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); @@ -1582,31 +1577,33 @@ static int deassert_reset(struct target *target) int dmi_busy_delay = info->dmi_busy_delay; time_t start = time(NULL); - LOG_DEBUG("Waiting for hart to be reset."); - do { - if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) - return ERROR_FAIL; + if (!riscv_havereset_not_supported) { + LOG_DEBUG("Waiting for hart %d to be reset.", r->current_hartid); + do { + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; - if (time(NULL) - start > riscv_reset_timeout_sec) { - LOG_ERROR("Hart didn't reset in %ds; dmstatus=0x%x; " - "Increase the timeout with riscv set_reset_timeout_sec.", - riscv_reset_timeout_sec, dmstatus); - return ERROR_FAIL; - } - } while (get_field(dmstatus, DMI_DMSTATUS_ALLHAVERESET) == 0); - /* Ack reset. */ - dmi_write(target, DMI_DMCONTROL, control | DMI_DMCONTROL_ACKHAVERESET); + if (time(NULL) - start > riscv_reset_timeout_sec) { + LOG_ERROR("Hart %d didn't reset in %ds; dmstatus=0x%x; " + "Increase the timeout with riscv set_reset_timeout_sec.", + r->current_hartid, riscv_reset_timeout_sec, dmstatus); + return ERROR_FAIL; + } + } while (get_field(dmstatus, DMI_DMSTATUS_ALLHAVERESET) == 0); + /* Ack reset. */ + dmi_write(target, DMI_DMCONTROL, control | DMI_DMCONTROL_ACKHAVERESET); + } if (target->reset_halt) { - LOG_DEBUG("Waiting for hart to be halted."); + LOG_DEBUG("Waiting for hart %d to be halted.", r->current_hartid); while (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0) { if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; if (time(NULL) - start > riscv_reset_timeout_sec) { - LOG_ERROR("Hart didn't halt coming out of reset in %ds; " + LOG_ERROR("Hart %d didn't halt coming out of reset in %ds; " "dmstatus=0x%x; " "Increase the timeout with riscv set_reset_timeout_sec.", - riscv_reset_timeout_sec, dmstatus); + r->current_hartid, riscv_reset_timeout_sec, dmstatus); return ERROR_FAIL; } } @@ -1616,21 +1613,21 @@ static int deassert_reset(struct target *target) dmi_write(target, DMI_DMCONTROL, control); } else { - LOG_DEBUG("Waiting for hart to be running."); + LOG_DEBUG("Waiting for hart %d to be running.", r->current_hartid); while (get_field(dmstatus, DMI_DMSTATUS_ALLRUNNING) == 0) { if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; if (get_field(dmstatus, DMI_DMSTATUS_ANYHALTED) || get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) { - LOG_ERROR("Unexpected hart status during reset. dmstatus=0x%x", - dmstatus); + LOG_ERROR("Unexpected hart %d status during reset. dmstatus=0x%x", + r->current_hartid, dmstatus); return ERROR_FAIL; } if (time(NULL) - start > riscv_reset_timeout_sec) { - LOG_ERROR("Hart didn't run coming out of reset in %ds; " + LOG_ERROR("Hart %d didn't run coming out of reset in %ds; " "dmstatus=0x%x; " "Increase the timeout with riscv set_reset_timeout_sec.", - riscv_reset_timeout_sec, dmstatus); + r->current_hartid, riscv_reset_timeout_sec, dmstatus); return ERROR_FAIL; } } @@ -2566,7 +2563,7 @@ static bool riscv013_is_halted(struct target *target) LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target)); if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target)); - if (get_field(dmstatus, DMI_DMSTATUS_ANYHAVERESET)) { + if (!riscv_havereset_not_supported && get_field(dmstatus, DMI_DMSTATUS_ANYHAVERESET)) { int hartid = riscv_current_hartid(target); LOG_INFO("Hart %d unexpectedly reset!", hartid); /* TODO: Can we make this more obvious to eg. a gdb user? */ diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 6b2658353..72afb855a 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -188,6 +188,8 @@ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; bool riscv_use_scratch_ram; uint64_t riscv_scratch_ram_address; +bool riscv_havereset_not_supported; + /* In addition to the ones in the standard spec, we'll also expose additional * CSRs in this list. * The list is either NULL, or a series of ranges (inclusive), terminated with @@ -1247,6 +1249,17 @@ COMMAND_HANDLER(riscv_set_scratch_ram) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_supports_havereset) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_havereset_not_supported); + riscv_havereset_not_supported = !riscv_havereset_not_supported; + return ERROR_OK; +} + void parse_error(const char *string, char c, unsigned position) { char buf[position+2]; @@ -1458,6 +1471,15 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "riscv set_scratch_ram none|[address]", .help = "Set address of 16 bytes of scratch RAM the debugger can use, or 'none'." }, + { + .name = "set_supports_havereset", + .handler = riscv_set_supports_havereset, + .mode = COMMAND_ANY, + .usage = "riscv set_supports_havereset on|off", + .help = "Set this off if one of the targets doesn't implement " + "allhavereset/anyhavereset in dmcontrol. When on, OpenOCD will wait " + "for these bits to go high during a reset." + }, { .name = "expose_csrs", .handler = riscv_set_expose_csrs, diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 1e6ffb94b..9bcf7f2c9 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -128,6 +128,9 @@ extern int riscv_reset_timeout_sec; extern bool riscv_use_scratch_ram; extern uint64_t riscv_scratch_ram_address; +/* Negative so that the default value of 0 is what we want. */ +extern bool riscv_havereset_not_supported; + /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));