Skip to content

deassert_reset should not wait for a target to come out of reset and should not update target->state #1216

@en-sc

Description

@en-sc

Currently there is a loop in deassert_reset() handler that waits for the hart to come out of reset.

LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset.");
do {
result = dmstatus_read(target, &dmstatus, true);
if (result != ERROR_OK)
return result;
if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; "
"dmstatus=0x%x (allunavail=%s, allhavereset=%s); "
"Increase the timeout with riscv set_command_timeout_sec.",
riscv_get_command_timeout_sec(), dmstatus,
get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) ? "true" : "false",
get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false");
return ERROR_TIMEOUT_REACHED;
}
/* Certain debug modules, like the one in GD32VF103
* MCUs, violate the specification's requirement that
* each hart is in "exactly one of four states" and,
* during reset, report harts as both unavailable and
* halted/running. To work around this, we check for
* the absence of the unavailable state rather than
* the presence of any other state. */
} while (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) &&
!get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET));

This is not necessary -- there is a call to arp_waitstate:

catch { $t arp_waitstate halted 1000 }

The task is to move handling of a target coming out of reset from deassert_reset() to poll(). This will also allow to drop the awkward handling of an unexpected reset in riscv013_get_hart_state():

if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) {
LOG_TARGET_INFO(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 |
DM_DMCONTROL_ACKHAVERESET;
dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
/* If we had been halted when we reset, request another halt. If we
* ended up running out of reset, then the user will (hopefully) get a
* message that a reset happened, that the target is running, and then
* that it is halted again once the request goes through.
*/
if (target->state == TARGET_HALTED) {
dmcontrol |= DM_DMCONTROL_HALTREQ;
/* `haltreq` should not be issued if `abstractcs.busy`
* is set. */
int result = wait_for_idle_if_needed(target);
if (result != ERROR_OK)
return result;
}
dm_write(target, DM_DMCONTROL, dmcontrol);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions