Dump some registers when hitting an unexpected exception
At the moment, no information is printed on the UART whenever we hit
an unexpected exception, not even an error message. This is not great
from the user's perspective, who has got no idea of what is going on.
Now we print an error message, as well as the state of some of the
registers. This includes general-purpose registers, as well as some
system registers.
This is implemented for TFTF running:
- in AArch64 state, at EL2;
- in AArch64 state, at NS-EL1;
- in AArch32 state.
We might want to dump more registers in the future but this patch
at least provides a basis we can build upon.
Also, the SP_EL0 has been removed from the list of registers saved in
the CPU context because TFTF always uses SP_ELx and does not touch
SP_EL0 at all.
Change-Id: I56e4afa917b53b5ccccff1d5d09ac8ccfaa6ae49
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
diff --git a/tftf/framework/aarch32/exception_report.c b/tftf/framework/aarch32/exception_report.c
new file mode 100644
index 0000000..46665e3
--- /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();
+}