aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Hoff <christian.hoff@advantest.com>2020-11-23 14:34:56 +0100
committerAntonio Borneo <borneo.antonio@gmail.com>2021-03-19 21:57:43 +0000
commit6c0151623cb09da6a80655cedf568db927ae2d93 (patch)
tree4b14f8cafac313e08f7ac1b2dbcad788f883f040
parent25218e8935037367e419219f8c855d92a3163023 (diff)
downloadriscv-openocd-6c0151623cb09da6a80655cedf568db927ae2d93.zip
riscv-openocd-6c0151623cb09da6a80655cedf568db927ae2d93.tar.gz
riscv-openocd-6c0151623cb09da6a80655cedf568db927ae2d93.tar.bz2
aarch64: add support for "reset halt"
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>
-rw-r--r--src/target/aarch64.c108
-rw-r--r--src/target/armv8_dpm.h7
2 files changed, 108 insertions, 7 deletions
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index d111a05..e458030 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -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,
diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h
index ee6f699..a6cade3 100644
--- a/src/target/armv8_dpm.h
+++ b/src/target/armv8_dpm.h
@@ -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)