1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2018 ARM Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "chip.h"
18 #include "dbg.h"
19 #include "uart.h"
20
21 #define mbed_error_printf dbg
22
23 /** MBED_NOINLINE
24 * Declare a function that must not be inlined.
25 *
26 * @code
27 * #include "mbed_toolchain.h"
28 *
29 * MBED_NOINLINE void foo() {
30 *
31 * }
32 * @endcode
33 */
34 #ifndef MBED_NOINLINE
35 #if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
36 #define MBED_NOINLINE __attribute__((noinline))
37 #elif defined(__ICCARM__)
38 #define MBED_NOINLINE _Pragma("inline=never")
39 #else
40 #define MBED_NOINLINE
41 #endif
42 #endif
43
44 #ifdef CFG_FHDLR
45 //Fault context struct
46 //WARNING: DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
47 //Offset of these registers are used by fault handler in except.S
48 typedef struct {
49 uint32_t R0_reg;
50 uint32_t R1_reg;
51 uint32_t R2_reg;
52 uint32_t R3_reg;
53 uint32_t R4_reg;
54 uint32_t R5_reg;
55 uint32_t R6_reg;
56 uint32_t R7_reg;
57 uint32_t R8_reg;
58 uint32_t R9_reg;
59 uint32_t R10_reg;
60 uint32_t R11_reg;
61 uint32_t R12_reg;
62 uint32_t SP_reg;
63 uint32_t LR_reg;
64 uint32_t PC_reg;
65 uint32_t xPSR;
66 uint32_t PSP;
67 uint32_t MSP;
68 uint32_t EXC_RETURN;
69 uint32_t CONTROL;
70 } mbed_fault_context_t;
71
72 typedef union {
73 struct {
74 union {
75 struct {
76 uint8_t IACCVIOL :1;
77 uint8_t DACCVIOL :1;
78 uint8_t :1;
79 uint8_t MUNSTKERR :1;
80 uint8_t MSTKERR :1;
81 uint8_t MLSPERR :1;
82 uint8_t :1;
83 uint8_t MMARVALID :1;
84 } MMFSR;
85 uint8_t BYTE_MMFSR;
86 };
87 union {
88 struct {
89 uint8_t IBUSERR :1;
90 uint8_t PRECISERR :1;
91 uint8_t IMPRECISERR :1;
92 uint8_t UNSTKERR :1;
93 uint8_t STKERR :1;
94 uint8_t LSPERR :1;
95 uint8_t :1;
96 uint8_t BFARVALID :1;
97 } BFSR;
98 uint8_t BYTE_BFSR;
99 };
100 union {
101 struct {
102 uint16_t UNDEFINSTR :1;
103 uint16_t INVSTATE :1;
104 uint16_t INVPC :1;
105 uint16_t NOCP :1;
106 uint16_t :4;
107 uint16_t UNALIGNED :1;
108 uint16_t DIVBYZERO :1;
109 uint16_t :6;
110 } UFSR;
111 uint16_t HALFWORD_UFSR;
112 };
113 };
114 uint32_t WORD;
115 } SCB_CFSR_REG_t;
116
117 //Fault type definitions
118 //WARNING: DO NOT CHANGE THESE VALUES WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
119 #define HARD_FAULT_EXCEPTION (0x10) //Keep some gap between values for any future insertion/expansion
120 #define MEMMANAGE_FAULT_EXCEPTION (0x20)
121 #define BUS_FAULT_EXCEPTION (0x30)
122 #define USAGE_FAULT_EXCEPTION (0x40)
123
124 //Functions Prototypes
125 void print_context_info(void);
126 void panic(void);
127
128 //Global for populating the context in exception handler
129 mbed_fault_context_t mbed_fault_context;
130
131 //This is a handler function called from Fault handler to print the error information out.
132 //This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support.
mbed_fault_handler(uint32_t fault_type,void * mbed_fault_context_in)133 void mbed_fault_handler(uint32_t fault_type, void *mbed_fault_context_in)
134 {
135 while (!ipc_mutex_get(IPC_MUTEX_UART_OUTPUT)); // lock mutex
136
137 mbed_error_printf("\n++ CM4 Fault Handler ++\n\nFaultType: ");
138
139 switch (fault_type) {
140 case MEMMANAGE_FAULT_EXCEPTION:
141 mbed_error_printf("MemManageFault");
142 break;
143
144 case BUS_FAULT_EXCEPTION:
145 mbed_error_printf("BusFault");
146 break;
147
148 case USAGE_FAULT_EXCEPTION:
149 mbed_error_printf("UsageFault");
150 break;
151
152 //There is no way we can hit this code without getting an exception, so we have the default treated like hardfault
153 case HARD_FAULT_EXCEPTION:
154 default:
155 mbed_error_printf("HardFault");
156 break;
157 }
158 mbed_error_printf("\n\nContext:");
159 print_context_info();
160
161 mbed_error_printf("\n\n-- CM4 Fault Handler --\n\n");
162
163 ipc_mutex_set(IPC_MUTEX_UART_OUTPUT, 1); // unlock mutex
164
165 //Now call panic, to halt the system
166 panic();
167
168 }
169
print_context_info(void)170 MBED_NOINLINE void print_context_info(void)
171 {
172 SCB_CFSR_REG_t CFSR_reg;
173
174 //Context Regs
175 for (int i=0;i<13;i++) {
176 mbed_error_printf("\nR%-4d: %08X", i, ((uint32_t *)&mbed_fault_context)[i]);
177 }
178
179 mbed_error_printf("\nSP : %08X"
180 "\nLR : %08X"
181 "\nPC : %08X"
182 "\nxPSR : %08X"
183 "\nPSP : %08X"
184 "\nMSP : %08X", mbed_fault_context.SP_reg, mbed_fault_context.LR_reg, mbed_fault_context.PC_reg,
185 mbed_fault_context.xPSR, mbed_fault_context.PSP, mbed_fault_context.MSP );
186
187 //Capture CPUID to get core/cpu info
188 mbed_error_printf("\nCPUID: %08X"
189 "\nICSR : %08X"
190 "\nVTOR : %08X"
191 "\nAIRCR: %08X"
192 , SCB->CPUID, SCB->ICSR, SCB->VTOR, SCB->AIRCR);
193
194 #if !defined(TARGET_M0) && !defined(TARGET_M0P)
195 //Capture fault information registers to infer the cause of exception
196 mbed_error_printf("\nSHCSR: %08X"
197 "\nCFSR : %08X"
198 "\nHFSR : %08X"
199 "\nDFSR : %08X"
200 "\nAFSR : %08X"
201 , SCB->SHCSR, SCB->CFSR, SCB->HFSR, SCB->DFSR, SCB->AFSR);
202
203 CFSR_reg.WORD = SCB->CFSR;
204 if (CFSR_reg.BYTE_MMFSR) {
205 mbed_error_printf("\nMMFSR: %02X"
206 "\n IACCVIOL :%d\tDACCVIOL :%d"
207 "\n MUNSTKERR:%d\tMSTKERR :%d"
208 "\n MLSPERR :%d\tMMARVALID:%d"
209 , CFSR_reg.BYTE_MMFSR
210 , CFSR_reg.MMFSR.IACCVIOL, CFSR_reg.MMFSR.DACCVIOL
211 , CFSR_reg.MMFSR.MUNSTKERR, CFSR_reg.MMFSR.MSTKERR
212 , CFSR_reg.MMFSR.MLSPERR, CFSR_reg.MMFSR.MMARVALID);
213 //Print MMFAR only if its valid as indicated by MMMFSR
214 if (CFSR_reg.MMFSR.MMARVALID) {
215 mbed_error_printf("\nMMFAR: %08X", SCB->MMFAR);
216 }
217 }
218 if (CFSR_reg.BYTE_BFSR) {
219 mbed_error_printf("\nBFSR : %02X"
220 "\n IBUSERR :%d\tPRECISERR:%d"
221 "\n IMPRECISERR:%d\tUNSTKERR :%d"
222 "\n STKERR :%d\tLSPERR :%d"
223 "\n BFARVALID :%d"
224 , CFSR_reg.BYTE_BFSR
225 , CFSR_reg.BFSR.IBUSERR, CFSR_reg.BFSR.PRECISERR
226 , CFSR_reg.BFSR.IMPRECISERR, CFSR_reg.BFSR.UNSTKERR
227 , CFSR_reg.BFSR.STKERR, CFSR_reg.BFSR.LSPERR
228 , CFSR_reg.BFSR.BFARVALID);
229 //Print BFAR only if its valid as indicated by BFSR
230 if (CFSR_reg.BFSR.BFARVALID) {
231 mbed_error_printf("\nBFAR : %08X", SCB->BFAR);
232 }
233 }
234 if (CFSR_reg.HALFWORD_UFSR) {
235 mbed_error_printf("\nUFSR : %04X"
236 "\n UNDEFINSTR:%d\tINVSTATE :%d"
237 "\n INVPC :%d\tNOCP :%d"
238 "\n UNALIGNED :%d\tDIVBYZERO:%d"
239 , CFSR_reg.HALFWORD_UFSR
240 , CFSR_reg.UFSR.UNDEFINSTR, CFSR_reg.UFSR.INVSTATE
241 , CFSR_reg.UFSR.INVPC, CFSR_reg.UFSR.NOCP
242 , CFSR_reg.UFSR.UNALIGNED, CFSR_reg.UFSR.DIVBYZERO);
243 }
244 #endif
245
246 //Print Mode
247 if (mbed_fault_context.EXC_RETURN & 0x8) {
248 mbed_error_printf("\nMode : Thread");
249 //Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
250 //Note that the CONTROL register captured still reflects the privilege status of the
251 //thread mode eventhough we are in Handler mode by the time we capture it.
252 if (mbed_fault_context.CONTROL & 0x1) {
253 mbed_error_printf("\nPriv : User");
254 } else {
255 mbed_error_printf("\nPriv : Privileged");
256 }
257 } else {
258 mbed_error_printf("\nMode : Handler");
259 mbed_error_printf("\nPriv : Privileged");
260 }
261 //Print Return Stack
262 if (mbed_fault_context.EXC_RETURN & 0x4) {
263 mbed_error_printf("\nStack: PSP");
264 } else {
265 mbed_error_printf("\nStack: MSP");
266 }
267
268 mbed_error_printf("\nCNTRL: %08X"
269 "\nPMASK: %08X"
270 "\nFMASK: %08X"
271 "\nBASEP: %08X"
272 , mbed_fault_context.CONTROL, __get_PRIMASK(), __get_FAULTMASK(), __get_BASEPRI());
273
274 if (mbed_fault_context.MSP) {
275 int32_t idx;
276 uint32_t addr = mbed_fault_context.MSP & ~0x0FUL;
277 mbed_error_printf("\nDumpMSP:");
278 for (idx = 0; idx < 64; idx++) {
279 if (!(addr & 0x0FUL)) {
280 mbed_error_printf("\n[%08x]:", addr);
281 }
282 mbed_error_printf(" %08X", *((uint32_t *)addr));
283 addr += 4;
284 }
285 }
286
287 if (mbed_fault_context.PSP) {
288 int32_t idx;
289 uint32_t addr = mbed_fault_context.PSP & ~0x0FUL;
290 mbed_error_printf("\nDumpPSP:");
291 for (idx = 0; idx < 64; idx++) {
292 if (!(addr & 0x0FUL)) {
293 mbed_error_printf("\n[%08x]:", addr);
294 }
295 mbed_error_printf(" %08X", *((uint32_t *)addr));
296 addr += 4;
297 }
298 }
299 }
300
panic(void)301 void panic(void)
302 {
303 mbed_error_printf("Panic...\n");
304 while (1);
305 }
306
307 #endif /* CFG_FHDLR */
308