Skip to content

Commit e88edb7

Browse files
authored
Merge pull request riscv-collab#1171 from lz-bro/handle-all-trigger-halt
target/riscv: Fix SMP group is in inconsistent state
2 parents fa7e235 + d5969d5 commit e88edb7

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,
@@ -4025,6 +4027,8 @@ int riscv_openocd_poll(struct target *target)
40254027
{
40264028
LOG_TARGET_DEBUG(target, "Polling all harts.");
40274029

4030+
struct riscv_info *i = riscv_info(target);
4031+
40284032
struct list_head *targets;
40294033

40304034
OOCD_LIST_HEAD(single_target_list);
@@ -4046,6 +4050,7 @@ int riscv_openocd_poll(struct target *target)
40464050
unsigned int should_resume = 0;
40474051
unsigned int halted = 0;
40484052
unsigned int running = 0;
4053+
unsigned int cause_groups = 0;
40494054
struct target_list *entry;
40504055
foreach_smp_target(entry, targets) {
40514056
struct target *t = entry->target;
@@ -4093,6 +4098,59 @@ int riscv_openocd_poll(struct target *target)
40934098
LOG_TARGET_DEBUG(target, "resume all");
40944099
riscv_resume(target, true, 0, 0, 0, false);
40954100
} else if (halted && running) {
4101+
LOG_TARGET_DEBUG(target, "SMP group is in inconsistent state: %u halted, %u running",
4102+
halted, running);
4103+
4104+
/* The SMP group is in an inconsistent state - some harts in the group have halted
4105+
* whereas others are running. The reasons for that (and corresponding
4106+
* OpenOCD actions) could be:
4107+
* 1) The targets are in the process of halting due to halt groups
4108+
* but not all of them halted --> poll again so that the halt reason of every
4109+
* hart can be accurately determined (e.g. semihosting).
4110+
* 2) The targets do not support halt groups --> OpenOCD must halt
4111+
* the remaining harts by a standard halt request.
4112+
* 3) The hart states got out of sync for some other unknown reason (problem?). -->
4113+
* Same as previous - try to halt the harts by a standard halt request
4114+
* to get them back in sync. */
4115+
4116+
/* Detect if the harts are just in the process of halting due to a halt group */
4117+
foreach_smp_target(entry, targets)
4118+
{
4119+
struct target *t = entry->target;
4120+
if (t->state == TARGET_HALTED) {
4121+
riscv_reg_t dcsr;
4122+
if (riscv_reg_get(t, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
4123+
return ERROR_FAIL;
4124+
if (get_field(dcsr, CSR_DCSR_CAUSE) == CSR_DCSR_CAUSE_GROUP)
4125+
cause_groups++;
4126+
else
4127+
/* This hart has halted due to something else than a halt group.
4128+
* Don't continue checking the rest - exit early. */
4129+
break;
4130+
}
4131+
}
4132+
/* Condition: halted == cause_groups
4133+
*
4134+
* This condition indicates a paradox where:
4135+
* - All currently halted harts show CSR_DCSR_CAUSE_GROUP
4136+
* - However, no individual hart can be identified as the actual initiator of the halt condition
4137+
*
4138+
* Poll again so that the true halt reason can be discovered (e.g. CSR_DCSR_CAUSE_EBREAK) */
4139+
if (halted == cause_groups) {
4140+
LOG_TARGET_DEBUG(target, "The harts appear to just be in the process of halting due to a halt group.");
4141+
if (i->halt_group_repoll_count < RISCV_HALT_GROUP_REPOLL_LIMIT) {
4142+
/* Wait a little, then re-poll. */
4143+
i->halt_group_repoll_count++;
4144+
alive_sleep(10);
4145+
LOG_TARGET_DEBUG(target, "Re-polling the state of the SMP group.");
4146+
return riscv_openocd_poll(target);
4147+
}
4148+
/* We have already re-polled multiple times but the halt group is still inconsistent. */
4149+
LOG_TARGET_DEBUG(target, "Re-polled the SMP group %d times it is still not in a consistent state.",
4150+
RISCV_HALT_GROUP_REPOLL_LIMIT);
4151+
}
4152+
4153+
/* Halting the whole SMP group to bring it in sync. */
40964154
LOG_TARGET_DEBUG(target, "halt all; halted=%d",
40974155
halted);
40984156
riscv_halt(target);
@@ -4110,6 +4168,8 @@ int riscv_openocd_poll(struct target *target)
41104168
}
41114169
}
41124170

4171+
i->halt_group_repoll_count = 0;
4172+
41134173
/* Call tick() for every hart. What happens in tick() is opaque to this
41144174
* layer. The reason it's outside the previous loop is that at this point
41154175
* 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
@@ -239,6 +239,7 @@ struct riscv_info {
239239
/* Used by riscv_openocd_poll(). */
240240
bool halted_needs_event_callback;
241241
enum target_event halted_callback_event;
242+
unsigned int halt_group_repoll_count;
242243

243244
enum riscv_isrmasking_mode isrmask_mode;
244245

0 commit comments

Comments
 (0)