target: fix messages and return values of failed op because not halted
[openocd.git] / src / target / cortex_m.c
index 1863441674ef3ba34f6b7f76909cbc4cb548f183..9541caa7921122f7a4bc152660052646daaff472 100644 (file)
@@ -28,6 +28,8 @@
 #include "register.h"
 #include "arm_opcodes.h"
 #include "arm_semihosting.h"
+#include "smp.h"
+#include <helper/nvp.h>
 #include <helper/time_support.h>
 #include <rtt/rtt.h>
 
@@ -799,15 +801,11 @@ static int cortex_m_debug_entry(struct target *target)
                return retval;
 
        /* examine PE security state */
-       bool secure_state = false;
+       uint32_t dscsr = 0;
        if (armv7m->arm.arch == ARM_ARCH_V8M) {
-               uint32_t dscsr;
-
                retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DSCSR, &dscsr);
                if (retval != ERROR_OK)
                        return retval;
-
-               secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS;
        }
 
        /* Load all registers to arm.core_cache */
@@ -855,6 +853,7 @@ static int cortex_m_debug_entry(struct target *target)
        if (armv7m->exception_number)
                cortex_m_examine_exception_reason(target);
 
+       bool secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS;
        LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32
                        ", cpu in %s state, target->state: %s",
                arm_mode_name(arm->core_mode),
@@ -871,7 +870,7 @@ static int cortex_m_debug_entry(struct target *target)
        return ERROR_OK;
 }
 
-static int cortex_m_poll(struct target *target)
+static int cortex_m_poll_one(struct target *target)
 {
        int detected_failure = ERROR_OK;
        int retval = ERROR_OK;
@@ -879,16 +878,6 @@ static int cortex_m_poll(struct target *target)
        struct cortex_m_common *cortex_m = target_to_cm(target);
        struct armv7m_common *armv7m = &cortex_m->armv7m;
 
-       /* Check if debug_ap is available to prevent segmentation fault.
-        * If the re-examination after an error does not find a MEM-AP
-        * (e.g. the target stopped communicating), debug_ap pointer
-        * can suddenly become NULL.
-        */
-       if (!armv7m->debug_ap) {
-               target->state = TARGET_UNKNOWN;
-               return ERROR_TARGET_NOT_EXAMINED;
-       }
-
        /* Read from Debug Halting Control and Status Register */
        retval = cortex_m_read_dhcsr_atomic_sticky(target);
        if (retval != ERROR_OK) {
@@ -944,21 +933,26 @@ 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;
 
-                       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+                       if (target->smp) {
+                               LOG_TARGET_DEBUG(target, "postpone target event 'halted'");
+                               target->smp_halt_event_postponed = true;
+                       } else {
+                               /* regardless 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 +985,104 @@ static int cortex_m_poll(struct target *target)
        return retval;
 }
 
-static int cortex_m_halt(struct target *target)
+static int cortex_m_halt_one(struct target *target);
+
+static int cortex_m_smp_halt_all(struct list_head *smp_targets)
+{
+       int retval = ERROR_OK;
+       struct target_list *head;
+
+       foreach_smp_target(head, smp_targets) {
+               struct target *curr = head->target;
+               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_smp_post_halt_poll(struct list_head *smp_targets)
+{
+       int retval = ERROR_OK;
+       struct target_list *head;
+
+       foreach_smp_target(head, smp_targets) {
+               struct target *curr = head->target;
+               if (!target_was_examined(curr))
+                       continue;
+               /* skip targets that were already halted */
+               if (curr->state == TARGET_HALTED)
+                       continue;
+
+               int ret2 = cortex_m_poll_one(curr);
+               if (retval == ERROR_OK)
+                       retval = ret2;  /* store the first error code ignore others */
+       }
+       return retval;
+}
+
+static int cortex_m_poll_smp(struct list_head *smp_targets)
+{
+       int retval = ERROR_OK;
+       struct target_list *head;
+       bool halted = false;
+
+       foreach_smp_target(head, smp_targets) {
+               struct target *curr = head->target;
+               if (curr->smp_halt_event_postponed) {
+                       halted = true;
+                       break;
+               }
+       }
+
+       if (halted) {
+               retval = cortex_m_smp_halt_all(smp_targets);
+
+               int ret2 = cortex_m_smp_post_halt_poll(smp_targets);
+               if (retval == ERROR_OK)
+                       retval = ret2;  /* store the first error code ignore others */
+
+               foreach_smp_target(head, smp_targets) {
+                       struct target *curr = head->target;
+                       if (!curr->smp_halt_event_postponed)
+                               continue;
+
+                       curr->smp_halt_event_postponed = false;
+                       if (curr->state == TARGET_HALTED) {
+                               LOG_TARGET_DEBUG(curr, "sending postponed target event 'halted'");
+                               target_call_event_callbacks(curr, TARGET_EVENT_HALTED);
+                       }
+               }
+               /* There is no need to set gdb_service->target
+                * as hwthread_update_threads() selects an interesting thread
+                * by its own
+                */
+       }
+       return retval;
+}
+
+static int cortex_m_poll(struct target *target)
+{
+       int retval = cortex_m_poll_one(target);
+
+       if (target->smp) {
+               struct target_list *last;
+               last = list_last_entry(target->smp_targets, struct target_list, lh);
+               if (target == last->target)
+                       /* After the last target in SMP group has been polled
+                        * check for postponed halted events and eventually halt and re-poll
+                        * other targets */
+                       cortex_m_poll_smp(target->smp_targets);
+       }
+       return retval;
+}
+
+static int cortex_m_halt_one(struct target *target)
 {
        LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target));
 
@@ -1029,6 +1120,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->smp_targets);
+       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 +1205,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 +1214,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, "not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
@@ -1157,7 +1256,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 +1270,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 +1285,99 @@ 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;
+       target_addr_t address;
+       foreach_smp_target(head, target->smp_targets) {
+               struct target *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, true, &address,
+                                                                               handle_breakpoints, false);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = cortex_m_restart_one(curr, false);
+               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)
@@ -1223,10 +1391,15 @@ static int cortex_m_step(struct target *target, int current,
        bool isr_timed_out = false;
 
        if (target->state != TARGET_HALTED) {
-               LOG_TARGET_WARNING(target, "target not halted");
+               LOG_TARGET_ERROR(target, "not halted");
                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);
@@ -1919,7 +2092,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo
 
        /* REVISIT why check? DWT can be updated with core running ... */
        if (target->state != TARGET_HALTED) {
-               LOG_TARGET_WARNING(target, "target not halted");
+               LOG_TARGET_ERROR(target, "not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
@@ -2280,6 +2453,22 @@ static void cortex_m_dwt_free(struct target *target)
        cm->dwt_cache = NULL;
 }
 
+static bool cortex_m_has_tz(struct target *target)
+{
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       uint32_t dauthstatus;
+
+       if (armv7m->arm.arch != ARM_ARCH_V8M)
+               return false;
+
+       int retval = target_read_u32(target, DAUTHSTATUS, &dauthstatus);
+       if (retval != ERROR_OK) {
+               LOG_WARNING("Error reading DAUTHSTATUS register");
+               return false;
+       }
+       return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0;
+}
+
 #define MVFR0 0xe000ef40
 #define MVFR1 0xe000ef44
 
@@ -2311,23 +2500,20 @@ int cortex_m_examine(struct target *target)
        /* hla_target shares the examine handler but does not support
         * all its calls */
        if (!armv7m->is_hla_target) {
-               if (armv7m->debug_ap) {
-                       dap_put_ap(armv7m->debug_ap);
-                       armv7m->debug_ap = NULL;
-               }
-
-               if (cortex_m->apsel == DP_APSEL_INVALID) {
-                       /* Search for the MEM-AP */
-                       retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap);
-                       if (retval != ERROR_OK) {
-                               LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core");
-                               return retval;
-                       }
-               } else {
-                       armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel);
-                       if (!armv7m->debug_ap) {
-                               LOG_ERROR("Cannot get AP");
-                               return ERROR_FAIL;
+               if (!armv7m->debug_ap) {
+                       if (cortex_m->apsel == DP_APSEL_INVALID) {
+                               /* Search for the MEM-AP */
+                               retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap);
+                               if (retval != ERROR_OK) {
+                                       LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core");
+                                       return retval;
+                               }
+                       } else {
+                               armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel);
+                               if (!armv7m->debug_ap) {
+                                       LOG_ERROR("Cannot get AP");
+                                       return ERROR_FAIL;
+                               }
                        }
                }
 
@@ -2411,7 +2597,7 @@ int cortex_m_examine(struct target *target)
                        for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++)
                                armv7m->arm.core_cache->reg_list[idx].exist = false;
 
-               if (armv7m->arm.arch != ARM_ARCH_V8M)
+               if (!cortex_m_has_tz(target))
                        for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++)
                                armv7m->arm.core_cache->reg_list[idx].exist = false;
 
@@ -2747,14 +2933,14 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command)
        struct cortex_m_common *cortex_m = target_to_cm(target);
        int retval;
 
-       static const struct jim_nvp nvp_maskisr_modes[] = {
+       static const struct nvp nvp_maskisr_modes[] = {
                { .name = "auto", .value = CORTEX_M_ISRMASK_AUTO },
                { .name = "off", .value = CORTEX_M_ISRMASK_OFF },
                { .name = "on", .value = CORTEX_M_ISRMASK_ON },
                { .name = "steponly", .value = CORTEX_M_ISRMASK_STEPONLY },
                { .name = NULL, .value = -1 },
        };
-       const struct jim_nvp *n;
+       const struct nvp *n;
 
 
        retval = cortex_m_verify_pointer(CMD, cortex_m);
@@ -2762,19 +2948,19 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command)
                return retval;
 
        if (target->state != TARGET_HALTED) {
-               command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
-               return ERROR_OK;
+               command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME);
+               return ERROR_TARGET_NOT_HALTED;
        }
 
        if (CMD_ARGC > 0) {
-               n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+               n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]);
                if (!n->name)
                        return ERROR_COMMAND_SYNTAX_ERROR;
                cortex_m->isrmasking_mode = n->value;
                cortex_m_set_maskints_for_halt(target);
        }
 
-       n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_m->isrmasking_mode);
+       n = nvp_value2name(nvp_maskisr_modes, cortex_m->isrmasking_mode);
        command_print(CMD, "cortex_m interrupt mask %s", n->name);
 
        return ERROR_OK;
@@ -2847,6 +3033,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[] = {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)