This is an automated email from Gerrit. "Tomas Vanek <van...@fbl.cz>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7239
-- gerrit commit 91434a191d593f9806af4824d0cfa7ea31bc2c04 Author: Tomas Vanek <van...@fbl.cz> Date: Sat Oct 1 17:10:31 2022 +0200 target/cortex_m: add SMP support for Cortex-M Cortex-M support for SMP multicore targets. Obsolete gdb 'J' packet/smp_gdb command core switching is not implemented, use with rtos hwthread. Only one core is resumed if debug_execution is requested. Some ideas taken from Graham Sanderson's [4936] and src/target/aarch64.c Added error checking of armv7m_restore_context(). Change-Id: I60f5b79e74b624dc2b5835ff10e38ac2ccb23792 Link: [4936]: target/cortex_m: Add smp support for Cortex M | https://review.openocd.org/c/openocd/+/4936 Signed-off-by: Tomas Vanek <van...@fbl.cz> diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 23d9065e2a..018b8ff765 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -28,6 +28,7 @@ #include "register.h" #include "arm_opcodes.h" #include "arm_semihosting.h" +#include "smp.h" #include <helper/time_support.h> #include <rtt/rtt.h> @@ -871,7 +872,57 @@ static int cortex_m_debug_entry(struct target *target) return ERROR_OK; } -static int cortex_m_poll(struct target *target) +static int cortex_m_halt_one(struct target *target); + +static int cortex_m_smp_halt_all(struct target *target, struct target *exclude) +{ + int retval = ERROR_OK; + struct target_list *head; + struct target *curr; + + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (curr == exclude) + continue; + if (!target_was_examined(curr)) + continue; + if (curr->state == TARGET_HALTED) + continue; + + int ret2 = cortex_m_halt_one(curr); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + } + return retval; +} + +static int cortex_m_poll_smp(struct target *target, bool is_smp); + +static int cortex_m_smp_post_halt_poll(struct target *target) +{ + int retval = ERROR_OK; + struct target_list *head; + struct target *curr; + + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + /* skip calling target */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + /* skip targets that were already halted */ + if (curr->state == TARGET_HALTED) + continue; + + int ret2 = cortex_m_poll_smp(curr, false); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + } + return retval; +} + +static int cortex_m_poll_smp(struct target *target, bool is_smp) { int detected_failure = ERROR_OK; int retval = ERROR_OK; @@ -944,21 +995,33 @@ static int cortex_m_poll(struct target *target) if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) { retval = cortex_m_debug_entry(target); - if (retval != ERROR_OK) - return retval; - if (arm_semihosting(target, &retval) != 0) + /* arm_semihosting needs to know registers, don't run if debug entry returned error */ + if (retval == ERROR_OK && arm_semihosting(target, &retval) != 0) return retval; + if (is_smp) { + if (target->gdb_service) + target->gdb_service->target = target; + + int ret2 = cortex_m_smp_halt_all(target, target); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + + ret2 = cortex_m_smp_post_halt_poll(target); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + } + /* regardles of errors returned in previous code update state */ target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (prev_target_state == TARGET_DEBUG_RUNNING) { retval = cortex_m_debug_entry(target); - if (retval != ERROR_OK) - return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } + if (retval != ERROR_OK) + return retval; } if (target->state == TARGET_UNKNOWN) { @@ -991,7 +1054,12 @@ static int cortex_m_poll(struct target *target) return retval; } -static int cortex_m_halt(struct target *target) +static int cortex_m_poll(struct target *target) +{ + return cortex_m_poll_smp(target, target->smp != 0); +} + +static int cortex_m_halt_one(struct target *target) { LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); @@ -1029,6 +1097,14 @@ static int cortex_m_halt(struct target *target) return ERROR_OK; } +static int cortex_m_halt(struct target *target) +{ + if (target->smp) + return cortex_m_smp_halt_all(target, NULL); + else + return cortex_m_halt_one(target); +} + static int cortex_m_soft_reset_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); @@ -1106,8 +1182,8 @@ void cortex_m_enable_breakpoints(struct target *target) } } -static int cortex_m_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int cortex_m_restore_one(struct target *target, bool current, + target_addr_t *address, bool handle_breakpoints, bool debug_execution) { struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; @@ -1115,7 +1191,7 @@ static int cortex_m_resume(struct target *target, int current, struct reg *r; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1157,7 +1233,7 @@ static int cortex_m_resume(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at <address> */ r = armv7m->arm.pc; if (!current) { - buf_set_u32(r->value, 0, 32, address); + buf_set_u32(r->value, 0, 32, *address); r->dirty = true; r->valid = true; } @@ -1171,8 +1247,12 @@ static int cortex_m_resume(struct target *target, int current, armv7m_maybe_skip_bkpt_inst(target, NULL); resume_pc = buf_get_u32(r->value, 0, 32); + if (current) + *address = resume_pc; - armv7m_restore_context(target); + int retval = armv7m_restore_context(target); + if (retval != ERROR_OK) + return retval; /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { @@ -1182,34 +1262,100 @@ static int cortex_m_resume(struct target *target, int current, LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); - cortex_m_unset_breakpoint(target, breakpoint); - cortex_m_single_step_core(target); - cortex_m_set_breakpoint(target, breakpoint); + retval = cortex_m_unset_breakpoint(target, breakpoint); + if (retval == ERROR_OK) + retval = cortex_m_single_step_core(target); + int ret2 = cortex_m_set_breakpoint(target, breakpoint); + if (retval != ERROR_OK) + return retval; + if (ret2 != ERROR_OK) + return ret2; } } + return ERROR_OK; +} + +static int cortex_m_restart_one(struct target *target, bool debug_execution) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + /* Restart core */ cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT); target->debug_reason = DBG_REASON_NOTHALTED; - /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_TARGET_DEBUG(target, "target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_TARGET_DEBUG(target, "target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } +static int cortex_m_restore_smp(struct target *target, bool handle_breakpoints) +{ + struct target_list *head; + struct target *curr; + target_addr_t address; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + /* skip calling target */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + /* skip running targets */ + if (curr->state == TARGET_RUNNING) + continue; + + int retval = cortex_m_restore_one(curr, 1, &address, + handle_breakpoints, 0); + if (retval != ERROR_OK) + return retval; + + retval = cortex_m_restart_one(curr, 0); + if (retval != ERROR_OK) + return retval; + + LOG_TARGET_DEBUG(curr, "SMP resumed at " TARGET_ADDR_FMT, address); + } + return ERROR_OK; +} + +static int cortex_m_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + int retval = cortex_m_restore_one(target, !!current, &address, !!handle_breakpoints, !!debug_execution); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "context restore failed, aborting resume"); + return retval; + } + + if (target->smp && !debug_execution) { + retval = cortex_m_restore_smp(target, !!handle_breakpoints); + if (retval != ERROR_OK) + LOG_WARNING("resume of a SMP target failed, trying to resume current one"); + } + + cortex_m_restart_one(target, !!debug_execution); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "resume failed"); + return retval; + } + + LOG_TARGET_DEBUG(target, "%sresumed at " TARGET_ADDR_FMT, + debug_execution ? "debug " : "", address); + + return ERROR_OK; +} + /* int irqstepcount = 0; */ static int cortex_m_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) @@ -1227,6 +1373,11 @@ static int cortex_m_step(struct target *target, int current, return ERROR_TARGET_NOT_HALTED; } + /* Just one of SMP cores will step. Set the gdb control + * target to current one or gdb miss gdb-end event */ + if (target->smp && target->gdb_service) + target->gdb_service->target = target; + /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); @@ -2829,6 +2980,9 @@ static const struct command_registration cortex_m_exec_command_handlers[] = { .help = "configure software reset handling", .usage = "['sysresetreq'|'vectreset']", }, + { + .chain = smp_command_handlers, + }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_m_command_handlers[] = { --