diff options
author | Christian Hoff <christian.hoff@advantest.com> | 2020-11-23 14:34:56 +0100 |
---|---|---|
committer | Antonio Borneo <borneo.antonio@gmail.com> | 2021-03-19 21:57:43 +0000 |
commit | 6c0151623cb09da6a80655cedf568db927ae2d93 (patch) | |
tree | 4b14f8cafac313e08f7ac1b2dbcad788f883f040 /src/target/aarch64.c | |
parent | 25218e8935037367e419219f8c855d92a3163023 (diff) | |
download | riscv-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>
Diffstat (limited to 'src/target/aarch64.c')
-rw-r--r-- | src/target/aarch64.c | 108 |
1 files changed, 101 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, |