• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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