Skip to content

Commit

Permalink
target/riscv: Fix SMP group is in inconsistent state
Browse files Browse the repository at this point in the history
If the harts are just in the process of halting due to
a halt group, poll again so that the halt reason of every
hart can be accurately determined (e.g. semihosting).
  • Loading branch information
lz-bro committed Feb 15, 2025
1 parent f51900b commit a573dc7
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/target/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

#define RISCV_TRIGGER_HIT_NOT_FOUND ((int64_t)-1)

#define RISCV_HALT_GROUP_REPOLL_LIMIT 5

static uint8_t ir_dtmcontrol[4] = {DTMCONTROL};
struct scan_field select_dtmcontrol = {
.in_value = NULL,
Expand Down Expand Up @@ -3722,6 +3724,8 @@ int riscv_openocd_poll(struct target *target)
{
LOG_TARGET_DEBUG(target, "Polling all harts.");

struct riscv_info *i = riscv_info(target);

struct list_head *targets;

LIST_HEAD(single_target_list);
Expand All @@ -3743,6 +3747,7 @@ int riscv_openocd_poll(struct target *target)
unsigned int should_resume = 0;
unsigned int halted = 0;
unsigned int running = 0;
unsigned int cause_groups = 0;
struct target_list *entry;
foreach_smp_target(entry, targets) {
struct target *t = entry->target;
Expand Down Expand Up @@ -3790,6 +3795,53 @@ int riscv_openocd_poll(struct target *target)
LOG_TARGET_DEBUG(target, "resume all");
riscv_resume(target, true, 0, 0, 0, false);
} else if (halted && running) {
LOG_TARGET_DEBUG(target, "SMP group is in inconsistent state: %u halted, %u running",
halted, running);

/* The SMP group is in an inconsistent state - some harts in the group have halted
* whereas others are running. The reasons for that (and corresponding
* OpenOCD actions) could be:
* 1) The targets are in the process of halting due to halt groups
* but not all of them halted --> poll again so that the halt reason of every
* hart can be accurately determined (e.g. semihosting).
* 2) The targets do not support halt groups --> OpenOCD must halt
* the remaining harts by a standard halt request.
* 3) The hart states got out of sync for some other unknown reason (problem?). -->
* Same as previous - try to halt the harts by a standard halt request
* to get them back in sync. */

/* Detect if the harts are just in the process of halting due to a halt group */
foreach_smp_target(entry, targets)
{
struct target *t = entry->target;
if (t->state == TARGET_HALTED) {
riscv_reg_t dcsr;
if (riscv_reg_get(t, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
if (get_field(dcsr, CSR_DCSR_CAUSE) == CSR_DCSR_CAUSE_GROUP)
cause_groups++;
else
/* This hart has halted due to something else than a halt group.
* Don't continue checking the rest - exit early. */
break;
}
}
if (halted == cause_groups) {
LOG_TARGET_DEBUG(target, "The harts appear to just be in the process of halting due to a halt group.");
if (i->halt_group_repoll_count < RISCV_HALT_GROUP_REPOLL_LIMIT) {
/* Wait a little, then re-poll. */
i->halt_group_repoll_count++;
alive_sleep(10);
LOG_TARGET_DEBUG(target, "Re-polling the state of the SMP group.");
return riscv_openocd_poll(target);
} else {
/* We have already re-polled multiple times but the halt group is still inconsistent. */
LOG_TARGET_DEBUG(target, "Re-polled the SMP group %d times it is still not "
"in a consistent state.", RISCV_HALT_GROUP_REPOLL_LIMIT);
}
}

/* Halting the whole SMP group to bring it in sync. */
LOG_TARGET_DEBUG(target, "halt all; halted=%d",
halted);
riscv_halt(target);
Expand All @@ -3807,6 +3859,8 @@ int riscv_openocd_poll(struct target *target)
}
}

i->halt_group_repoll_count = 0;

/* Call tick() for every hart. What happens in tick() is opaque to this
* layer. The reason it's outside the previous loop is that at this point
* the state of every hart has settled, so any side effects happening in
Expand Down
1 change: 1 addition & 0 deletions src/target/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ struct riscv_info {
/* Used by riscv_openocd_poll(). */
bool halted_needs_event_callback;
enum target_event halted_callback_event;
unsigned int halt_group_repoll_count;

enum riscv_isrmasking_mode isrmask_mode;

Expand Down

0 comments on commit a573dc7

Please sign in to comment.