openocd: fix SPDX tag format for files .c
[fw/openocd] / src / target / cortex_m.c
index 108f7e790cf8a8d7d7bdf6aeb5c331e2d7503511..23d9065e2a7e09ccb36fa8b56e7e66260cbc8719 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
@@ -8,19 +10,6 @@
  *   Copyright (C) 2008 by Spencer Oliver                                  *
  *   spen@spen-soft.co.uk                                                  *
  *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
- *                                                                         *
  *                                                                         *
  *   Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0)              *
  *                                                                         *
@@ -114,6 +103,12 @@ static const struct cortex_m_part_info cortex_m_parts[] = {
                .arch = ARM_ARCH_V8M,
                .flags = CORTEX_M_F_HAS_FPV5,
        },
+       {
+               .partno = STAR_MC1_PARTNO,
+               .name = "STAR-MC1",
+               .arch = ARM_ARCH_V8M,
+               .flags = CORTEX_M_F_HAS_FPV5,
+       },
 };
 
 /* forward declarations */
@@ -663,6 +658,11 @@ static int cortex_m_endreset_event(struct target *target)
 
        register_cache_invalidate(armv7m->arm.core_cache);
 
+       /* TODO: invalidate also working areas (needed in the case of detected reset).
+        * Doing so will require flash drivers to test if working area
+        * is still valid in all target algo calling loops.
+        */
+
        /* make sure we have latest dhcsr flags */
        retval = cortex_m_read_dhcsr_atomic_sticky(target);
        if (retval != ERROR_OK)
@@ -775,7 +775,7 @@ static int cortex_m_examine_exception_reason(struct target *target)
 
 static int cortex_m_debug_entry(struct target *target)
 {
-       uint32_t xPSR;
+       uint32_t xpsr;
        int retval;
        struct cortex_m_common *cortex_m = target_to_cm(target);
        struct armv7m_common *armv7m = &cortex_m->armv7m;
@@ -826,11 +826,11 @@ static int cortex_m_debug_entry(struct target *target)
                return retval;
 
        r = arm->cpsr;
-       xPSR = buf_get_u32(r->value, 0, 32);
+       xpsr = buf_get_u32(r->value, 0, 32);
 
        /* Are we in an exception handler */
-       if (xPSR & 0x1FF) {
-               armv7m->exception_number = (xPSR & 0x1FF);
+       if (xpsr & 0x1FF) {
+               armv7m->exception_number = (xpsr & 0x1FF);
 
                arm->core_mode = ARM_MODE_HANDLER;
                arm->map = armv7m_msp_reg_map;
@@ -879,6 +879,16 @@ 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) {
@@ -1090,7 +1100,7 @@ void cortex_m_enable_breakpoints(struct target *target)
 
        /* set any pending breakpoints */
        while (breakpoint) {
-               if (!breakpoint->set)
+               if (!breakpoint->is_set)
                        cortex_m_set_breakpoint(target, breakpoint);
                breakpoint = breakpoint->next;
        }
@@ -1578,7 +1588,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
        struct cortex_m_common *cortex_m = target_to_cm(target);
        struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list;
 
-       if (breakpoint->set) {
+       if (breakpoint->is_set) {
                LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id);
                return ERROR_OK;
        }
@@ -1591,7 +1601,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
                        LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
-               breakpoint->set = fp_num + 1;
+               breakpoint_hw_set(breakpoint, fp_num);
                fpcr_value = breakpoint->address | 1;
                if (cortex_m->fp_rev == 0) {
                        if (breakpoint->address > 0x1FFFFFFF) {
@@ -1643,15 +1653,15 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
                                code);
                if (retval != ERROR_OK)
                        return retval;
-               breakpoint->set = true;
+               breakpoint->is_set = true;
        }
 
-       LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)",
+       LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)",
                breakpoint->unique_id,
                (int)(breakpoint->type),
                breakpoint->address,
                breakpoint->length,
-               breakpoint->set);
+               (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number);
 
        return ERROR_OK;
 }
@@ -1662,20 +1672,20 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi
        struct cortex_m_common *cortex_m = target_to_cm(target);
        struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list;
 
-       if (breakpoint->set <= 0) {
+       if (!breakpoint->is_set) {
                LOG_TARGET_WARNING(target, "breakpoint not set");
                return ERROR_OK;
        }
 
-       LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)",
+       LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)",
                breakpoint->unique_id,
                (int)(breakpoint->type),
                breakpoint->address,
                breakpoint->length,
-               breakpoint->set);
+               (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number);
 
        if (breakpoint->type == BKPT_HARD) {
-               unsigned int fp_num = breakpoint->set - 1;
+               unsigned int fp_num = breakpoint->number;
                if (fp_num >= cortex_m->fp_num_code) {
                        LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint");
                        return ERROR_OK;
@@ -1692,7 +1702,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi
                if (retval != ERROR_OK)
                        return retval;
        }
-       breakpoint->set = false;
+       breakpoint->is_set = false;
 
        return ERROR_OK;
 }
@@ -1714,7 +1724,7 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint
 
 int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
 {
-       if (!breakpoint->set)
+       if (!breakpoint->is_set)
                return ERROR_OK;
 
        return cortex_m_unset_breakpoint(target, breakpoint);
@@ -1741,7 +1751,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat
                return ERROR_FAIL;
        }
        comparator->used = true;
-       watchpoint->set = dwt_num + 1;
+       watchpoint_set(watchpoint, dwt_num);
 
        comparator->comp = watchpoint->address;
        target_write_u32(target, comparator->dwt_comparator_address + 0,
@@ -1808,15 +1818,15 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w
        struct cortex_m_common *cortex_m = target_to_cm(target);
        struct cortex_m_dwt_comparator *comparator;
 
-       if (watchpoint->set <= 0) {
+       if (!watchpoint->is_set) {
                LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set",
                        watchpoint->unique_id);
                return ERROR_OK;
        }
 
-       unsigned int dwt_num = watchpoint->set - 1;
+       unsigned int dwt_num = watchpoint->number;
 
-       LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d address: 0x%08x clear",
+       LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: 0x%08x clear",
                watchpoint->unique_id, dwt_num,
                (unsigned) watchpoint->address);
 
@@ -1831,7 +1841,7 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w
        target_write_u32(target, comparator->dwt_comparator_address + 8,
                comparator->function);
 
-       watchpoint->set = false;
+       watchpoint->is_set = false;
 
        return ERROR_OK;
 }
@@ -1895,7 +1905,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       if (watchpoint->set)
+       if (watchpoint->is_set)
                cortex_m_unset_watchpoint(target, watchpoint);
 
        cortex_m->dwt_comp_available++;
@@ -1904,7 +1914,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo
        return ERROR_OK;
 }
 
-int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
+static int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
 {
        if (target->debug_reason != DBG_REASON_WATCHPOINT)
                return ERROR_FAIL;
@@ -1912,10 +1922,10 @@ int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watch
        struct cortex_m_common *cortex_m = target_to_cm(target);
 
        for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) {
-               if (!wp->set)
+               if (!wp->is_set)
                        continue;
 
-               unsigned int dwt_num = wp->set - 1;
+               unsigned int dwt_num = wp->number;
                struct cortex_m_dwt_comparator *comparator = cortex_m->dwt_comparator_list + dwt_num;
 
                uint32_t dwt_function;
@@ -1939,7 +1949,7 @@ void cortex_m_enable_watchpoints(struct target *target)
 
        /* set any pending watchpoints */
        while (watchpoint) {
-               if (!watchpoint->set)
+               if (!watchpoint->is_set)
                        cortex_m_set_watchpoint(target, watchpoint);
                watchpoint = watchpoint->next;
        }
@@ -1984,6 +1994,10 @@ static int cortex_m_init_target(struct command_context *cmd_ctx,
 void cortex_m_deinit_target(struct target *target)
 {
        struct cortex_m_common *cortex_m = target_to_cm(target);
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+
+       if (!armv7m->is_hla_target && armv7m->debug_ap)
+               dap_put_ap(armv7m->debug_ap);
 
        free(cortex_m->fp_comparator_list);
 
@@ -2262,10 +2276,10 @@ static void cortex_m_dwt_free(struct target *target)
 static int cortex_m_find_mem_ap(struct adiv5_dap *swjdp,
                struct adiv5_ap **debug_ap)
 {
-       if (dap_find_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK)
+       if (dap_find_get_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK)
                return ERROR_OK;
 
-       return dap_find_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap);
+       return dap_find_get_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap);
 }
 
 int cortex_m_examine(struct target *target)
@@ -2279,6 +2293,11 @@ 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);
@@ -2287,7 +2306,11 @@ int cortex_m_examine(struct target *target)
                                return retval;
                        }
                } else {
-                       armv7m->debug_ap = dap_ap(swjdp, cortex_m->apsel);
+                       armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel);
+                       if (!armv7m->debug_ap) {
+                               LOG_ERROR("Cannot get AP");
+                               return ERROR_FAIL;
+                       }
                }
 
                armv7m->debug_ap->memaccess_tck = 8;
@@ -2384,6 +2407,20 @@ int cortex_m_examine(struct target *target)
                retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr);
                if (retval != ERROR_OK)
                        return retval;
+
+               /*  Don't cumulate sticky S_RESET_ST at the very first read of DHCSR
+                *  as S_RESET_ST may indicate a reset that happened long time ago
+                *  (most probably the power-on reset before OpenOCD was started).
+                *  As we are just initializing the debug system we do not need
+                *  to call cortex_m_endreset_event() in the following poll.
+                */
+               if (!cortex_m->dcb_dhcsr_sticky_is_recent) {
+                       cortex_m->dcb_dhcsr_sticky_is_recent = true;
+                       if (cortex_m->dcb_dhcsr & S_RESET_ST) {
+                               LOG_TARGET_DEBUG(target, "reset happened some time ago, ignore");
+                               cortex_m->dcb_dhcsr &= ~S_RESET_ST;
+                       }
+               }
                cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr);
 
                if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) {