aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandrine Bailleux <sandrine.bailleux@arm.com>2019-01-28 07:40:15 +0000
committerTrustedFirmware Code Review <review@review.trustedfirmware.org>2019-01-28 07:40:15 +0000
commit6d7047dcb24325e0a782b47c0ad507b6a5b32746 (patch)
tree7e8496ca50786a6f38e42a9d00c944c73738f1b7
parent09a00ef98c6108fec75dafcc7dbdddacb2ee2e91 (diff)
parenta43b003acd6c8e8991a57e993f7bfcdfaa04f980 (diff)
downloadtf-a-tests-6d7047dcb24325e0a782b47c0ad507b6a5b32746.tar.gz
Merge changes from topic "sb/exception-dump"
* changes: Dump some registers when hitting an unexpected exception Improve readability of TFTF exceptions code
-rw-r--r--include/lib/aarch32/arch.h1
-rw-r--r--include/lib/aarch32/arch_helpers.h2
-rw-r--r--tftf/framework/aarch32/exception_report.c53
-rw-r--r--tftf/framework/aarch32/exceptions.S24
-rw-r--r--tftf/framework/aarch64/exception_report.c60
-rw-r--r--tftf/framework/aarch64/exceptions.S105
-rw-r--r--tftf/framework/framework.mk1
7 files changed, 176 insertions, 70 deletions
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 71013a74..9b466018 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -514,6 +514,7 @@
#define ATS1CPR p15, 0, c7, c8, 0
#define ATS1HR p15, 4, c7, c8, 0
#define DBGOSDLR p14, 0, c1, c3, 4
+#define HSR p15, 4, c5, c2, 0
/* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
#define HDCR p15, 4, c1, c1, 1
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index cbca7165..e9835547 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -201,6 +201,7 @@ DEFINE_SYSOP_FUNC(isb)
DEFINE_SYSREG_RW_FUNCS(spsr)
DEFINE_SYSREG_RW_FUNCS(cpsr)
+DEFINE_SYSREG_RW_FUNCS(elr_hyp)
/*******************************************************************************
* System register accessor prototypes
@@ -213,6 +214,7 @@ DEFINE_COPROCR_READ_FUNC(id_pfr1, ID_PFR1)
DEFINE_COPROCR_READ_FUNC(isr, ISR)
DEFINE_COPROCR_READ_FUNC(clidr, CLIDR)
DEFINE_COPROCR_READ_FUNC_64(cntpct, CNTPCT_64)
+DEFINE_COPROCR_READ_FUNC(hsr, HSR)
DEFINE_COPROCR_RW_FUNCS(scr, SCR)
DEFINE_COPROCR_RW_FUNCS(ctr, CTR)
diff --git a/tftf/framework/aarch32/exception_report.c b/tftf/framework/aarch32/exception_report.c
new file mode 100644
index 00000000..46665e3e
--- /dev/null
+++ b/tftf/framework/aarch32/exception_report.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <platform.h>
+#include <utils_def.h>
+
+/* We save r0-r12. */
+#define GPREGS_CNT 13
+
+/* Set of registers saved by the crash_dump() assembly function. */
+struct cpu_context {
+ u_register_t regs[GPREGS_CNT];
+ u_register_t lr;
+ u_register_t sp;
+};
+
+void __dead2 print_exception(const struct cpu_context *ctx)
+{
+ u_register_t mpid = read_mpidr();
+
+ /*
+ * The instruction barrier ensures we don't read stale values of system
+ * registers.
+ */
+ isb();
+
+ printf("Unhandled exception on CPU%u.\n", platform_get_core_pos(mpid));
+
+ /* Dump some interesting system registers. */
+ printf("System registers:\n");
+ printf(" MPIDR=0x%lx\n", mpid);
+ printf(" HSR=0x%lx ELR=0x%lx SPSR=0x%lx\n", read_hsr(),
+ read_elr_hyp(), read_spsr());
+
+ /* Dump general-purpose registers. */
+ printf("General-purpose registers:\n");
+ for (int i = 0; i < GPREGS_CNT; ++i) {
+ printf(" r%u=0x%lx\n", i, ctx->regs[i]);
+ }
+ printf(" LR=0x%lx\n", ctx->lr);
+ printf(" SP=0x%lx\n", ctx->sp);
+
+ while (1)
+ wfi();
+}
diff --git a/tftf/framework/aarch32/exceptions.S b/tftf/framework/aarch32/exceptions.S
index 1e6c574d..aaeb93c1 100644
--- a/tftf/framework/aarch32/exceptions.S
+++ b/tftf/framework/aarch32/exceptions.S
@@ -12,13 +12,23 @@
vector_base tftf_vector
b tftf_entrypoint
- b . /* Undef */
- b . /* Syscall */
- b . /* Prefetch abort */
- b . /* Data abort */
- b . /* Hyp trap */
- b tftf_intr_handle/* IRQ */
- b . /* FIQ */
+ b crash_dump /* Undef */
+ b crash_dump /* Syscall */
+ b crash_dump /* Prefetch abort */
+ b crash_dump /* Data abort */
+ b crash_dump /* Hyp trap */
+ b tftf_intr_handle /* IRQ */
+ b crash_dump /* FIQ */
+
+func crash_dump
+ /* Save SP and general-purpose registers on the stack. */
+ push {sp}
+ push {r0-r12, lr}
+
+ /* Print the saved CPU context on the UART. */
+ mov r0, sp
+ b print_exception
+endfunc crash_dump
/* ----------------------------------------------------------------------------
* The IRQ exception handler
diff --git a/tftf/framework/aarch64/exception_report.c b/tftf/framework/aarch64/exception_report.c
new file mode 100644
index 00000000..0add2764
--- /dev/null
+++ b/tftf/framework/aarch64/exception_report.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <platform.h>
+#include <utils_def.h>
+
+/* We save x0-x30. */
+#define GPREGS_CNT 31
+
+/* Set of registers saved by the crash_dump() assembly function. */
+struct cpu_context {
+ u_register_t regs[GPREGS_CNT];
+ u_register_t sp;
+};
+
+/*
+ * Read the EL1 or EL2 version of a register, depending on the current exception
+ * level.
+ */
+#define read_sysreg(_name) \
+ (IS_IN_EL2() ? read_##_name##_el2() : read_##_name##_el1())
+
+void __dead2 print_exception(const struct cpu_context *ctx)
+{
+ u_register_t mpid = read_mpidr_el1();
+
+ /*
+ * The instruction barrier ensures we don't read stale values of system
+ * registers.
+ */
+ isb();
+
+ printf("Unhandled exception on CPU%u.\n", platform_get_core_pos(mpid));
+
+ /* Dump some interesting system registers. */
+ printf("System registers:\n");
+ printf(" MPIDR=0x%lx\n", mpid);
+ printf(" ESR=0x%lx ELR=0x%lx FAR=0x%lx\n", read_sysreg(esr),
+ read_sysreg(elr), read_sysreg(far));
+ printf(" SCTLR=0x%lx SPSR=0x%lx DAIF=0x%lx\n",
+ read_sysreg(sctlr), read_sysreg(spsr), read_daif());
+
+ /* Dump general-purpose registers. */
+ printf("General-purpose registers:\n");
+ for (int i = 0; i < GPREGS_CNT; ++i) {
+ printf(" x%u=0x%lx\n", i, ctx->regs[i]);
+ }
+ printf(" SP=0x%lx\n", ctx->sp);
+
+ while (1)
+ wfi();
+}
diff --git a/tftf/framework/aarch64/exceptions.S b/tftf/framework/aarch64/exceptions.S
index 6014b12e..677b30fe 100644
--- a/tftf/framework/aarch64/exceptions.S
+++ b/tftf/framework/aarch64/exceptions.S
@@ -8,88 +8,54 @@
.globl tftf_vector
+/*
+ * Exception vector code for unhandled exceptions.
+ * Print a crash dump on the UART and loops forever.
+ */
+.macro unhandled_exception name
+ vector_entry \name
+ b crash_dump
+ end_vector_entry \name
+.endm
+
vector_base tftf_vector
/*
* Current EL with SP0 : 0x0 - 0x200.
*/
-vector_entry SynchronousExceptionSP0
- b SynchronousExceptionSP0
-end_vector_entry SynchronousExceptionSP0
-
-vector_entry IrqSP0
- b IrqSP0
-end_vector_entry IrqSP0
-
-vector_entry FiqSP0
- b FiqSP0
-end_vector_entry FiqSP0
-
-vector_entry SErrorSP0
- b SErrorSP0
-end_vector_entry SErrorSP0
+unhandled_exception SynchronousExceptionSP0
+unhandled_exception IrqSP0
+unhandled_exception FiqSP0
+unhandled_exception SErrorSP0
/*
* Current EL with SPx : 0x200 - 0x400.
*/
-vector_entry SynchronousExceptionSPx
- b SynchronousExceptionSPx
-end_vector_entry SynchronousExceptionSPx
+unhandled_exception SynchronousExceptionSPx
vector_entry IrqSPx
b irq_vector_entry
end_vector_entry IrqSPx
-vector_entry FiqSPx
- b FiqSPx
-end_vector_entry FiqSPx
-
-vector_entry SErrorSPx
- b SErrorSPx
-end_vector_entry SErrorSPx
+unhandled_exception FiqSPx
+unhandled_exception SErrorSPx
/*
* Lower EL using AArch64 : 0x400 - 0x600.
*/
-vector_entry SynchronousExceptionA64
- b SynchronousExceptionA64
-end_vector_entry SynchronousExceptionA64
-
-vector_entry IrqA64
- b IrqA64
-end_vector_entry IrqA64
-
-vector_entry FiqA64
- b FiqA64
-end_vector_entry FiqA64
-
-vector_entry SErrorA64
- b SErrorA64
-end_vector_entry SErrorA64
+unhandled_exception SynchronousExceptionA64
+unhandled_exception IrqA64
+unhandled_exception FiqA64
+unhandled_exception SErrorA64
/*
* Lower EL using AArch32 : 0x600 - 0x800.
*/
-vector_entry SynchronousExceptionA32
- b SynchronousExceptionA32
-end_vector_entry SynchronousExceptionA32
+unhandled_exception SynchronousExceptionA32
+unhandled_exception IrqA32
+unhandled_exception FiqA32
+unhandled_exception SErrorA32
-vector_entry IrqA32
- b IrqA32
-end_vector_entry IrqA32
-
-vector_entry FiqA32
- b FiqA32
-end_vector_entry FiqA32
-
-vector_entry SErrorA32
- b SErrorA32
-end_vector_entry SErrorA32
-
-/*
- * Exceptions will always be from the same exception level so no need to save
- * and restore SPSR.
- */
.macro save_gp_regs
stp x0, x1, [sp, #0x0]
stp x2, x3, [sp, #0x10]
@@ -106,13 +72,12 @@ end_vector_entry SErrorA32
stp x24, x25, [sp, #0xc0]
stp x26, x27, [sp, #0xd0]
stp x28, x29, [sp, #0xe0]
- mrs x0, sp_el0
- stp x30, x0, [sp, #0xf0]
+ /* We push xzr simply to keep the stack 16-byte aligned. */
+ stp x30, xzr, [sp, #0xf0]
.endm
.macro restore_gp_regs
- ldp x30, x0, [sp, #0xf0]
- msr sp_el0, x0
+ ldp x30, xzr, [sp, #0xf0]
ldp x28, x29, [sp, #0xe0]
ldp x26, x27, [sp, #0xd0]
ldp x24, x25, [sp, #0xc0]
@@ -138,3 +103,17 @@ func irq_vector_entry
add sp, sp, #0x100
eret
endfunc irq_vector_entry
+
+func crash_dump
+ /* Save general-purpose registers on the stack. */
+ sub sp, sp, #0x100
+ save_gp_regs
+
+ /* Save original stack pointer value on the stack. */
+ add x1, sp, #0x100
+ str x1, [sp, #0xf8]
+
+ /* Print the saved CPU context on the UART. */
+ mov x0, sp
+ b print_exception
+endfunc crash_dump
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index 4e5dc2e6..36b29b23 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -51,6 +51,7 @@ FRAMEWORK_SOURCES += $(addprefix tftf/, \
framework/${ARCH}/asm_debug.S \
framework/${ARCH}/entrypoint.S \
framework/${ARCH}/exceptions.S \
+ framework/${ARCH}/exception_report.c \
framework/debug.c \
framework/main.c \
framework/nvm_results_helpers.c \