Skip to content

Commit d5969d5

Browse files
committed
target/riscv: Fix SMP group is in inconsistent state
If the harts are just in the process of halting due to being members of the halt group, we should wait until they finish halting, so that the true halt reason can be discovered (e.g. semihosting request, and then handled correctly).
1 parent f51900b commit d5969d5

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

src/target/riscv/riscv.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
#define RISCV_TRIGGER_HIT_NOT_FOUND ((int64_t)-1)
3939

40+
#define RISCV_HALT_GROUP_REPOLL_LIMIT 5
41+
4042
static uint8_t ir_dtmcontrol[4] = {DTMCONTROL};
4143
struct scan_field select_dtmcontrol = {
4244
.in_value = NULL,
@@ -3722,6 +3724,8 @@ int riscv_openocd_poll(struct target *target)
37223724
{
37233725
LOG_TARGET_DEBUG(target, "Polling all harts.");
37243726

3727+
struct riscv_info *i = riscv_info(target);
3728+
37253729
struct list_head *targets;
37263730

37273731
LIST_HEAD(single_target_list);
@@ -3743,6 +3747,7 @@ int riscv_openocd_poll(struct target *target)
37433747
unsigned int should_resume = 0;
37443748
unsigned int halted = 0;
37453749
unsigned int running = 0;
3750+
unsigned int cause_groups = 0;
37463751
struct target_list *entry;
37473752
foreach_smp_target(entry, targets) {
37483753
struct target *t = entry->target;
@@ -3790,6 +3795,59 @@ int riscv_openocd_poll(struct target *target)
37903795
LOG_TARGET_DEBUG(target, "resume all");
37913796
riscv_resume(target, true, 0, 0, 0, false);
37923797
} else if (halted && running) {
3798+
LOG_TARGET_DEBUG(target, "SMP group is in inconsistent state: %u halted, %u running",
3799+
halted, running);
3800+
3801+
/* The SMP group is in an inconsistent state - some harts in the group have halted
3802+
* whereas others are running. The reasons for that (and corresponding
3803+
* OpenOCD actions) could be:
3804+
* 1) The targets are in the process of halting due to halt groups
3805+
* but not all of them halted --> poll again so that the halt reason of every
3806+
* hart can be accurately determined (e.g. semihosting).
3807+
* 2) The targets do not support halt groups --> OpenOCD must halt
3808+
* the remaining harts by a standard halt request.
3809+
* 3) The hart states got out of sync for some other unknown reason (problem?). -->
3810+
* Same as previous - try to halt the harts by a standard halt request
3811+
* to get them back in sync. */
3812+
3813+
/* Detect if the harts are just in the process of halting due to a halt group */
3814+
foreach_smp_target(entry, targets)
3815+
{
3816+
struct target *t = entry->target;
3817+
if (t->state == TARGET_HALTED) {
3818+
riscv_reg_t dcsr;
3819+
if (riscv_reg_get(t, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
3820+
return ERROR_FAIL;
3821+
if (get_field(dcsr, CSR_DCSR_CAUSE) == CSR_DCSR_CAUSE_GROUP)
3822+
cause_groups++;
3823+
else
3824+
/* This hart has halted due to something else than a halt group.
3825+
* Don't continue checking the rest - exit early. */
3826+
break;
3827+
}
3828+
}
3829+
/* Condition: halted == cause_groups
3830+
*
3831+
* This condition indicates a paradox where:
3832+
* - All currently halted harts show CSR_DCSR_CAUSE_GROUP
3833+
* - However, no individual hart can be identified as the actual initiator of the halt condition
3834+
*
3835+
* Poll again so that the true halt reason can be discovered (e.g. CSR_DCSR_CAUSE_EBREAK) */
3836+
if (halted == cause_groups) {
3837+
LOG_TARGET_DEBUG(target, "The harts appear to just be in the process of halting due to a halt group.");
3838+
if (i->halt_group_repoll_count < RISCV_HALT_GROUP_REPOLL_LIMIT) {
3839+
/* Wait a little, then re-poll. */
3840+
i->halt_group_repoll_count++;
3841+
alive_sleep(10);
3842+
LOG_TARGET_DEBUG(target, "Re-polling the state of the SMP group.");
3843+
return riscv_openocd_poll(target);
3844+
}
3845+
/* We have already re-polled multiple times but the halt group is still inconsistent. */
3846+
LOG_TARGET_DEBUG(target, "Re-polled the SMP group %d times it is still not in a consistent state.",
3847+
RISCV_HALT_GROUP_REPOLL_LIMIT);
3848+
}
3849+
3850+
/* Halting the whole SMP group to bring it in sync. */
37933851
LOG_TARGET_DEBUG(target, "halt all; halted=%d",
37943852
halted);
37953853
riscv_halt(target);
@@ -3807,6 +3865,8 @@ int riscv_openocd_poll(struct target *target)
38073865
}
38083866
}
38093867

3868+
i->halt_group_repoll_count = 0;
3869+
38103870
/* Call tick() for every hart. What happens in tick() is opaque to this
38113871
* layer. The reason it's outside the previous loop is that at this point
38123872
* the state of every hart has settled, so any side effects happening in

src/target/riscv/riscv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ struct riscv_info {
193193
/* Used by riscv_openocd_poll(). */
194194
bool halted_needs_event_callback;
195195
enum target_event halted_callback_event;
196+
unsigned int halt_group_repoll_count;
196197

197198
enum riscv_isrmasking_mode isrmask_mode;
198199

0 commit comments

Comments
 (0)