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:
parent
25218e8935
commit
6c0151623c
|
@ -1677,21 +1677,101 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b
|
||||||
* Cortex-A8 Reset functions
|
* 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)
|
static int aarch64_assert_reset(struct target *target)
|
||||||
{
|
{
|
||||||
struct armv8_common *armv8 = target_to_armv8(target);
|
struct armv8_common *armv8 = target_to_armv8(target);
|
||||||
|
enum reset_types reset_config = jtag_get_reset_config();
|
||||||
|
int retval;
|
||||||
|
|
||||||
LOG_DEBUG(" ");
|
LOG_DEBUG(" ");
|
||||||
|
|
||||||
/* FIXME when halt is requested, make it work somehow... */
|
|
||||||
|
|
||||||
/* Issue some kind of warm reset. */
|
/* Issue some kind of warm reset. */
|
||||||
if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT))
|
if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT))
|
||||||
target_handle_event(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
|
/* REVISIT handle "pulls" cases, if there's
|
||||||
* hardware that needs them to work.
|
* hardware that needs them to work.
|
||||||
*/
|
*/
|
||||||
|
if (!srst_asserted)
|
||||||
adapter_assert_reset();
|
adapter_assert_reset();
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("%s: how to reset?", target_name(target));
|
LOG_ERROR("%s: how to reset?", target_name(target));
|
||||||
|
@ -1721,23 +1801,37 @@ static int aarch64_deassert_reset(struct target *target)
|
||||||
if (!target_was_examined(target))
|
if (!target_was_examined(target))
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
retval = aarch64_poll(target);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
retval = aarch64_init_debug_access(target);
|
retval = aarch64_init_debug_access(target);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
retval = aarch64_poll(target);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
if (target->reset_halt) {
|
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) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
LOG_WARNING("%s: ran after reset and before halt ...",
|
||||||
target_name(target));
|
target_name(target));
|
||||||
retval = target_halt(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,
|
static int aarch64_write_cpu_memory_slow(struct target *target,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define OPENOCD_TARGET_ARMV8_DPM_H
|
#define OPENOCD_TARGET_ARMV8_DPM_H
|
||||||
|
|
||||||
#include "arm_dpm.h"
|
#include "arm_dpm.h"
|
||||||
|
#include "helper/bits.h"
|
||||||
|
|
||||||
/* forward-declare struct armv8_common */
|
/* forward-declare struct armv8_common */
|
||||||
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_RESTART (1 << 1)
|
||||||
#define DRCR_CLEAR_EXCEPTIONS (1 << 2)
|
#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 */
|
/* PRSR (processor debug status register) bits */
|
||||||
#define PRSR_PU (1 << 0)
|
#define PRSR_PU (1 << 0)
|
||||||
#define PRSR_SPD (1 << 1)
|
#define PRSR_SPD (1 << 1)
|
||||||
|
|
Loading…
Reference in New Issue