target/aarch64: fix semihosting on SMP

Semihosting worked only on the first/gdb assigned core of a SMP group.
If a semihosting call was issued on another core, aarch64_update_halt_gdb()
emitted 'halted' event on core0 before semihosting decoding started.

Use target's smp_halt_event_postponed flag to keep events from emitting
until semihosting is decoded. If a semihosting call is confirmed,
clear flags and do not send 'halted' event for any core of SMP group.

Change-Id: Ie7eff7e493c2a4df3039f49fce1744d996050a59
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: https://review.openocd.org/c/openocd/+/9246
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
This commit is contained in:
Tomas Vanek
2025-11-21 12:21:16 +01:00
committed by Antonio Borneo
parent 1ca34e23c0
commit c2fdc38d32

View File

@@ -39,7 +39,8 @@ struct aarch64_private_config {
struct arm_cti *cti; struct arm_cti *cti;
}; };
static int aarch64_poll_smp(struct target *target, bool smp); static int aarch64_poll_smp(struct target *target, bool smp,
bool postpone_event);
static int aarch64_debug_entry(struct target *target); static int aarch64_debug_entry(struct target *target);
static int aarch64_restore_context(struct target *target, bool bpwp); static int aarch64_restore_context(struct target *target, bool bpwp);
static int aarch64_set_breakpoint(struct target *target, static int aarch64_set_breakpoint(struct target *target,
@@ -471,7 +472,6 @@ static int aarch64_halt_smp(struct target *target, bool exc_target)
static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reason debug_reason)
{ {
struct target *gdb_target = NULL;
struct target_list *head; struct target_list *head;
struct target *curr; struct target *curr;
@@ -480,7 +480,7 @@ static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reas
aarch64_halt_smp(target, true); aarch64_halt_smp(target, true);
} }
/* poll all targets in the group, but skip the target that serves GDB */ /* poll all targets in the group */
foreach_smp_target(head, target->smp_targets) { foreach_smp_target(head, target->smp_targets) {
curr = head->target; curr = head->target;
/* skip calling context */ /* skip calling context */
@@ -491,31 +491,43 @@ static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reas
/* skip targets that were already halted */ /* skip targets that were already halted */
if (curr->state == TARGET_HALTED) if (curr->state == TARGET_HALTED)
continue; continue;
/* remember the gdb_service->target */
if (curr->gdb_service)
gdb_target = curr->gdb_service->target;
/* skip it */
if (curr == gdb_target)
continue;
const bool smp = false; const bool smp = false;
aarch64_poll_smp(curr, smp); const bool postpone_event = true;
} aarch64_poll_smp(curr, smp, postpone_event);
/* after all targets were updated, poll the gdb serving target */
if (gdb_target && gdb_target != target) {
const bool smp = false;
aarch64_poll_smp(gdb_target, smp);
} }
return ERROR_OK; return ERROR_OK;
} }
enum postponed_halt_events_op {
POSTPONED_HALT_EVENT_CLEAR,
POSTPONED_HALT_EVENT_EMIT
};
static void aarch64_smp_postponed_halt_events(struct list_head *smp_targets,
enum postponed_halt_events_op op)
{
struct target_list *head;
foreach_smp_target(head, smp_targets) {
struct target *t = head->target;
if (!t->smp_halt_event_postponed)
continue;
if (op == POSTPONED_HALT_EVENT_EMIT) {
LOG_TARGET_DEBUG(t, "sending postponed target event 'halted'");
target_call_event_callbacks(t, TARGET_EVENT_HALTED);
}
t->smp_halt_event_postponed = false;
}
}
/* /*
* Aarch64 Run control * Aarch64 Run control
*/ */
static int aarch64_poll_smp(struct target *target, bool smp) static int aarch64_poll_smp(struct target *target, bool smp,
bool postpone_event)
{ {
struct armv8_common *armv8 = target_to_armv8(target); struct armv8_common *armv8 = target_to_armv8(target);
enum target_state prev_target_state; enum target_state prev_target_state;
@@ -553,13 +565,21 @@ static int aarch64_poll_smp(struct target *target, bool smp)
if (smp) if (smp)
aarch64_update_halt_gdb(target, debug_reason); aarch64_update_halt_gdb(target, debug_reason);
if (arm_semihosting(target, &retval) != 0) if (arm_semihosting(target, &retval) != 0) {
if (smp)
aarch64_smp_postponed_halt_events(target->smp_targets,
POSTPONED_HALT_EVENT_CLEAR);
return retval; return retval;
}
switch (prev_target_state) { switch (prev_target_state) {
case TARGET_RUNNING: case TARGET_RUNNING:
case TARGET_UNKNOWN: case TARGET_UNKNOWN:
case TARGET_RESET: case TARGET_RESET:
if (postpone_event)
target->smp_halt_event_postponed = true;
else
target_call_event_callbacks(target, TARGET_EVENT_HALTED); target_call_event_callbacks(target, TARGET_EVENT_HALTED);
break; break;
case TARGET_DEBUG_RUNNING: case TARGET_DEBUG_RUNNING:
@@ -568,6 +588,10 @@ static int aarch64_poll_smp(struct target *target, bool smp)
default: default:
break; break;
} }
if (smp)
aarch64_smp_postponed_halt_events(target->smp_targets,
POSTPONED_HALT_EVENT_EMIT);
} }
} else if (prsr & PRSR_RESET) { } else if (prsr & PRSR_RESET) {
target->state = TARGET_RESET; target->state = TARGET_RESET;
@@ -580,7 +604,8 @@ static int aarch64_poll_smp(struct target *target, bool smp)
static int aarch64_poll(struct target *target) static int aarch64_poll(struct target *target)
{ {
return aarch64_poll_smp(target, target->smp != 0); const bool postpone_event = false;
return aarch64_poll_smp(target, target->smp != 0, postpone_event);
} }
static int aarch64_halt(struct target *target) static int aarch64_halt(struct target *target)