Cortex-M3 vector_catch testing support
[openocd.git] / testing / examples / cortex / fault.c
1 /*
2 * COMPILE: arm-none-eabi-gcc -mthumb -march=armv7-m ...
3 * ... plus, provide at least a default exception vector table.
4 *
5 * RUN: this is best run from SRAM. It starts at main() then triggers
6 * a fault before more than a handful of instructions have executed.
7 * Run each test case in two modes:
8 *
9 * (1) Faults caught on the Cortex-M3. Default handlers are usually
10 * loop-to-self NOPs, so a debugger won't notice faults until they
11 * halt the core and examine xSPR and other registers.
12 *
13 * To verify the fault triggered, issue "halt" from OpenOCD; you
14 * should be told about the fault and (some of) its details.
15 * Then it's time to run the next test.
16 *
17 * NOTE however that "reset" will restart everything; verify that
18 * case by observing your reset handler doing its normal work.
19 *
20 * (2) Faults intercepted by OpenOCD "vector_catch ..." commands.
21 *
22 * OpenOCD should tell you about the fault, and show the same
23 * details, without your "halt" command.
24 *
25 * Someday, a fancy version of this code could provide a vector table and
26 * fault handlers which use semihosting (when that works on Cortex-M3) to
27 * report what happened, again without needing a "halt" command.
28 */
29
30
31 /* These symbols match the OpenOCD "cortex_m3 vector_catch" bit names. */
32 enum vc_case {
33 hard_err,
34 int_err,
35 bus_err,
36 state_err,
37 chk_err,
38 nocp_err,
39 mm_err,
40 reset,
41 };
42
43 /* REVISIT come up with a way to avoid recompiling, maybe:
44 * - write it in RAM before starting
45 * - compiled-in BKPT, manual patch of r0, then resume
46 * - ...
47 */
48
49 #ifndef VC_ID
50 #warning "no VC_ID ... using reset"
51 #define VC_ID reset
52 #endif
53
54 int main(void) __attribute__ ((externally_visible, noreturn));
55
56 /*
57 * Trigger various Cortex-M3 faults to verify that OpenOCD behaves OK
58 * in terms of its vector_catch handling.
59 *
60 * Fault handling should be left entirely up to the application code
61 * UNLESS a "vector_catch" command tells OpenOCD to intercept a fault.
62 *
63 * See ARMv7-M architecure spec table B1-9 for the list of faults and
64 * their mappings to the vector catch bits.
65 */
66 int main(void)
67 {
68 /* One test case for each vector catch bit. We're not doing
69 * hardware testing; so it doesn't matter when some DEMCR bits
70 * could apply in multiple ways.
71 */
72 switch (VC_ID) {
73
74 /* "cortex_m3 vector_catch hard_err" */
75 case hard_err:
76 /* FORCED - Fault escalation */
77
78 /* FIXME code this */
79 break;
80
81 /* "cortex_m3 vector_catch int_err" */
82 case int_err:
83 /* STKERR -- Exception stack BusFault */
84
85 /* FIXME code this */
86 break;
87
88 /* "cortex_m3 vector_catch bus_err" */
89 case bus_err:
90 /* PRECISERR -- precise data bus read
91 * Here we assume a Cortex-M3 with 512 MBytes SRAM is very
92 * unlikely, so the last SRAM byte isn't a valid address.
93 */
94 __asm__ volatile(
95 "mov r0, #0x3fffffff\n"
96 "ldrb r0, [r0]\n"
97 );
98 break;
99
100 /* "cortex_m3 vector_catch state_err" */
101 case state_err:
102 /* UNDEFINSTR -- architectural undefined instruction */
103 __asm__ volatile(".hword 0xde00");
104 break;
105
106 /* "cortex_m3 vector_catch chk_err" */
107 case chk_err:
108 /* UNALIGNED ldm */
109 __asm__ volatile(
110 "mov r0, #1\n"
111 "ldm r0, {r1, r2}\n"
112 );
113 break;
114
115 /* "cortex_m3 vector_catch nocp_err" */
116 case nocp_err:
117 /* NOCP ... Cortex-M3 has no coprocessors (like CP14 DCC),
118 * but these instructions are allowed by ARMv7-M.
119 */
120 __asm__ volatile("mrc p14, 0, r0, c0, c5, 0");
121 break;
122
123 /* "cortex_m3 vector_catch mm_err" */
124 case mm_err:
125 /* IACCVIOL -- instruction fetch from an XN region */
126 __asm__ volatile(
127 "mov r0, #0xe0000000\n"
128 "mov pc, r0\n"
129 );
130 break;
131
132 /* "cortex_m3 vector_catch reset" */
133 case reset:
134 __asm__ volatile(
135 /* r1 = SYSRESETREQ */
136 "mov r1, #0x0004\n"
137 /* r1 |= VECTKEY */
138 "movt r1, #0x05fa\n"
139 /* r0 = &AIRCR */
140 "mov r0, #0xed00\n"
141 "add r0, #0xc\n"
142 "movt r0, #0xe000\n"
143 /* AIRCR = ... */
144 "str r1, [r0, #0]\n"
145 );
146 break;
147 }
148
149 /* don't return */
150 while (1)
151 continue;
152 }