summaryrefslogtreecommitdiff
path: root/testing/examples/cortex/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'testing/examples/cortex/fault.c')
-rw-r--r--testing/examples/cortex/fault.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/testing/examples/cortex/fault.c b/testing/examples/cortex/fault.c
new file mode 100644
index 00000000..9a5fe194
--- /dev/null
+++ b/testing/examples/cortex/fault.c
@@ -0,0 +1,152 @@
+/*
+ * COMPILE: arm-none-eabi-gcc -mthumb -march=armv7-m ...
+ * ... plus, provide at least a default exception vector table.
+ *
+ * RUN: this is best run from SRAM. It starts at main() then triggers
+ * a fault before more than a handful of instructions have executed.
+ * Run each test case in two modes:
+ *
+ * (1) Faults caught on the Cortex-M3. Default handlers are usually
+ * loop-to-self NOPs, so a debugger won't notice faults until they
+ * halt the core and examine xSPR and other registers.
+ *
+ * To verify the fault triggered, issue "halt" from OpenOCD; you
+ * should be told about the fault and (some of) its details.
+ * Then it's time to run the next test.
+ *
+ * NOTE however that "reset" will restart everything; verify that
+ * case by observing your reset handler doing its normal work.
+ *
+ * (2) Faults intercepted by OpenOCD "vector_catch ..." commands.
+ *
+ * OpenOCD should tell you about the fault, and show the same
+ * details, without your "halt" command.
+ *
+ * Someday, a fancy version of this code could provide a vector table and
+ * fault handlers which use semihosting (when that works on Cortex-M3) to
+ * report what happened, again without needing a "halt" command.
+ */
+
+
+/* These symbols match the OpenOCD "cortex_m3 vector_catch" bit names. */
+enum vc_case {
+ hard_err,
+ int_err,
+ bus_err,
+ state_err,
+ chk_err,
+ nocp_err,
+ mm_err,
+ reset,
+};
+
+/* REVISIT come up with a way to avoid recompiling, maybe:
+ * - write it in RAM before starting
+ * - compiled-in BKPT, manual patch of r0, then resume
+ * - ...
+ */
+
+#ifndef VC_ID
+#warning "no VC_ID ... using reset"
+#define VC_ID reset
+#endif
+
+int main(void) __attribute__ ((externally_visible, noreturn));
+
+/*
+ * Trigger various Cortex-M3 faults to verify that OpenOCD behaves OK
+ * in terms of its vector_catch handling.
+ *
+ * Fault handling should be left entirely up to the application code
+ * UNLESS a "vector_catch" command tells OpenOCD to intercept a fault.
+ *
+ * See ARMv7-M architecure spec table B1-9 for the list of faults and
+ * their mappings to the vector catch bits.
+ */
+int main(void)
+{
+ /* One test case for each vector catch bit. We're not doing
+ * hardware testing; so it doesn't matter when some DEMCR bits
+ * could apply in multiple ways.
+ */
+ switch (VC_ID) {
+
+ /* "cortex_m3 vector_catch hard_err" */
+ case hard_err:
+ /* FORCED - Fault escalation */
+
+ /* FIXME code this */
+ break;
+
+ /* "cortex_m3 vector_catch int_err" */
+ case int_err:
+ /* STKERR -- Exception stack BusFault */
+
+ /* FIXME code this */
+ break;
+
+ /* "cortex_m3 vector_catch bus_err" */
+ case bus_err:
+ /* PRECISERR -- precise data bus read
+ * Here we assume a Cortex-M3 with 512 MBytes SRAM is very
+ * unlikely, so the last SRAM byte isn't a valid address.
+ */
+ __asm__ volatile(
+ "mov r0, #0x3fffffff\n"
+ "ldrb r0, [r0]\n"
+ );
+ break;
+
+ /* "cortex_m3 vector_catch state_err" */
+ case state_err:
+ /* UNDEFINSTR -- architectural undefined instruction */
+ __asm__ volatile(".hword 0xde00");
+ break;
+
+ /* "cortex_m3 vector_catch chk_err" */
+ case chk_err:
+ /* UNALIGNED ldm */
+ __asm__ volatile(
+ "mov r0, #1\n"
+ "ldm r0, {r1, r2}\n"
+ );
+ break;
+
+ /* "cortex_m3 vector_catch nocp_err" */
+ case nocp_err:
+ /* NOCP ... Cortex-M3 has no coprocessors (like CP14 DCC),
+ * but these instructions are allowed by ARMv7-M.
+ */
+ __asm__ volatile("mrc p14, 0, r0, c0, c5, 0");
+ break;
+
+ /* "cortex_m3 vector_catch mm_err" */
+ case mm_err:
+ /* IACCVIOL -- instruction fetch from an XN region */
+ __asm__ volatile(
+ "mov r0, #0xe0000000\n"
+ "mov pc, r0\n"
+ );
+ break;
+
+ /* "cortex_m3 vector_catch reset" */
+ case reset:
+ __asm__ volatile(
+ /* r1 = SYSRESETREQ */
+ "mov r1, #0x0004\n"
+ /* r1 |= VECTKEY */
+ "movt r1, #0x05fa\n"
+ /* r0 = &AIRCR */
+ "mov r0, #0xed00\n"
+ "add r0, #0xc\n"
+ "movt r0, #0xe000\n"
+ /* AIRCR = ... */
+ "str r1, [r0, #0]\n"
+ );
+ break;
+ }
+
+ /* don't return */
+ while (1)
+ continue;
+}