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>
This commit is contained in:
Christian Hoff 2020-11-23 14:34:56 +01:00 committed by Antonio Borneo
parent 25218e8935
commit 6c0151623c
2 changed files with 110 additions and 9 deletions

View 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);
if (retval != ERROR_OK)
return retval;
retval = aarch64_init_debug_access(target);
if (retval != ERROR_OK)
return retval;
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,

View 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)