aarch64: add support for "reset halt"
authorChristian Hoff <christian.hoff@advantest.com>
Mon, 23 Nov 2020 13:34:56 +0000 (14:34 +0100)
committerAntonio Borneo <borneo.antonio@gmail.com>
Fri, 19 Mar 2021 21:57:43 +0000 (21:57 +0000)
Support halting the CPU directly after a reset. If halt is
requested, the CPU stops directly at the reset vector, before
any code is executed.

This functionality was implemented using the Reset Catch
debug event.

Change-Id: If90d54c088442340376f0b588ba10267ea8e7327
Signed-off-by: Christian Hoff <christian.hoff@advantest.com>
Reviewed-on: http://openocd.zylin.com/5947
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
src/target/aarch64.c
src/target/armv8_dpm.h

index d111a05687730464f06b362dc97469c344af9d60..e45803040baac5897ef6ee03724be78ecf899ac9 100644 (file)
@@ -1677,22 +1677,102 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b
  * Cortex-A8 Reset functions
  */
 
+static int aarch64_enable_reset_catch(struct target *target, bool enable)
+{
+       struct armv8_common *armv8 = target_to_armv8(target);
+       uint32_t edecr;
+       int retval;
+
+       retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+                       armv8->debug_base + CPUV8_DBG_EDECR, &edecr);
+       LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (enable)
+               edecr |= ECR_RCE;
+       else
+               edecr &= ~ECR_RCE;
+
+       return mem_ap_write_atomic_u32(armv8->debug_ap,
+                       armv8->debug_base + CPUV8_DBG_EDECR, edecr);
+}
+
+static int aarch64_clear_reset_catch(struct target *target)
+{
+       struct armv8_common *armv8 = target_to_armv8(target);
+       uint32_t edesr;
+       int retval;
+       bool was_triggered;
+
+       /* check if Reset Catch debug event triggered as expected */
+       retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+               armv8->debug_base + CPUV8_DBG_EDESR, &edesr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       was_triggered = !!(edesr & ESR_RC);
+       LOG_DEBUG("Reset Catch debug event %s",
+                       was_triggered ? "triggered" : "NOT triggered!");
+
+       if (was_triggered) {
+               /* clear pending Reset Catch debug event */
+               edesr &= ~ESR_RC;
+               retval = mem_ap_write_atomic_u32(armv8->debug_ap,
+                       armv8->debug_base + CPUV8_DBG_EDESR, edesr);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
 static int aarch64_assert_reset(struct target *target)
 {
        struct armv8_common *armv8 = target_to_armv8(target);
+       enum reset_types reset_config = jtag_get_reset_config();
+       int retval;
 
        LOG_DEBUG(" ");
 
-       /* FIXME when halt is requested, make it work somehow... */
-
        /* Issue some kind of warm reset. */
        if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT))
                target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
-       else if (jtag_get_reset_config() & RESET_HAS_SRST) {
+       else if (reset_config & RESET_HAS_SRST) {
+               bool srst_asserted = false;
+
+               if (target->reset_halt) {
+                       if (target_was_examined(target)) {
+
+                               if (reset_config & RESET_SRST_NO_GATING) {
+                                       /*
+                                        * SRST needs to be asserted *before* Reset Catch
+                                        * debug event can be set up.
+                                        */
+                                       adapter_assert_reset();
+                                       srst_asserted = true;
+
+                                       /* make sure to clear all sticky errors */
+                                       mem_ap_write_atomic_u32(armv8->debug_ap,
+                                                       armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE);
+                               }
+
+                               /* set up Reset Catch debug event to halt the CPU after reset */
+                               retval = aarch64_enable_reset_catch(target, true);
+                               if (retval != ERROR_OK)
+                                       LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!",
+                                                       target_name(target));
+                       } else {
+                               LOG_WARNING("%s: Target not examined, will not halt immediately after reset!",
+                                               target_name(target));
+                       }
+               }
+
                /* REVISIT handle "pulls" cases, if there's
                 * hardware that needs them to work.
                 */
-               adapter_assert_reset();
+               if (!srst_asserted)
+                       adapter_assert_reset();
        } else {
                LOG_ERROR("%s: how to reset?", target_name(target));
                return ERROR_FAIL;
@@ -1721,23 +1801,37 @@ static int aarch64_deassert_reset(struct target *target)
        if (!target_was_examined(target))
                return ERROR_OK;
 
-       retval = aarch64_poll(target);
+       retval = aarch64_init_debug_access(target);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = aarch64_init_debug_access(target);
+       retval = aarch64_poll(target);
        if (retval != ERROR_OK)
                return retval;
 
        if (target->reset_halt) {
+               /* clear pending Reset Catch debug event */
+               retval = aarch64_clear_reset_catch(target);
+               if (retval != ERROR_OK)
+                       LOG_WARNING("%s: Clearing Reset Catch debug event failed",
+                                       target_name(target));
+
+               /* disable Reset Catch debug event */
+               retval = aarch64_enable_reset_catch(target, false);
+               if (retval != ERROR_OK)
+                       LOG_WARNING("%s: Disabling Reset Catch debug event failed",
+                                       target_name(target));
+
                if (target->state != TARGET_HALTED) {
                        LOG_WARNING("%s: ran after reset and before halt ...",
                                target_name(target));
                        retval = target_halt(target);
+                       if (retval != ERROR_OK)
+                               return retval;
                }
        }
 
-       return retval;
+       return ERROR_OK;
 }
 
 static int aarch64_write_cpu_memory_slow(struct target *target,
index ee6f699de2a07db16f0d0b12979db7300b6ddf2a..a6cade345e169d7fc6cb3bece4b9a230cc337d96 100644 (file)
@@ -16,6 +16,7 @@
 #define OPENOCD_TARGET_ARMV8_DPM_H
 
 #include "arm_dpm.h"
+#include "helper/bits.h"
 
 /* forward-declare struct armv8_common */
 struct armv8_common;
@@ -96,6 +97,12 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t wfar);
 #define DRCR_RESTART                   (1 << 1)
 #define DRCR_CLEAR_EXCEPTIONS  (1 << 2)
 
+/* ECR (Execution Control Register) bits */
+#define ECR_RCE         BIT(1)
+
+/* ESR (Event Status Register) bits */
+#define ESR_RC          BIT(1)
+
 /* PRSR (processor debug status register) bits */
 #define PRSR_PU                                        (1 << 0)
 #define PRSR_SPD                               (1 << 1)