|
17 | 17 | #include "rtx_os.h"
|
18 | 18 | #include "device.h"
|
19 | 19 | #include "platform/mbed_error.h"
|
| 20 | +#include "platform/mbed_interface.h" |
20 | 21 | #include "hal/serial_api.h"
|
21 |
| -#include "hal/itm_api.h" |
22 | 22 |
|
23 | 23 | #ifndef MBED_FAULT_HANDLER_DISABLED
|
24 | 24 | #include "mbed_rtx_fault_handler.h"
|
25 | 25 |
|
26 |
| -#ifdef DEVICE_SERIAL |
27 |
| -extern int stdio_uart_inited; |
28 |
| -extern serial_t stdio_uart; |
29 |
| -#endif |
30 |
| - |
31 | 26 | //Functions Prototypes
|
32 | 27 | void print_context_info(void);
|
33 | 28 |
|
34 | 29 | //Global for populating the context in exception handler
|
35 | 30 | mbed_fault_context_t mbed_fault_context;
|
36 | 31 |
|
37 |
| -/* Converts a uint32 to hex char string */ |
38 |
| -static void value_to_hex_str(uint32_t value, char *hex_str) |
39 |
| -{ |
40 |
| - char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; |
41 |
| - int i = 0; |
42 |
| - |
43 |
| - //Return without converting if hex_str is not provided |
44 |
| - if(hex_str == NULL) return; |
45 |
| - |
46 |
| - for(i=7; i>=0; i--) { |
47 |
| - hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)]; |
48 |
| - } |
49 |
| -} |
50 |
| - |
51 |
| -static void fault_print_init(void) |
52 |
| -{ |
53 |
| -#if DEVICE_SERIAL |
54 |
| - /* Initializes std uart if not init-ed yet */ |
55 |
| - if (!stdio_uart_inited) { |
56 |
| - serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); |
57 |
| - } |
58 |
| -#endif |
59 |
| - |
60 |
| -#if DEVICE_ITM |
61 |
| - /*Initialize ITM interfaces*/ |
62 |
| - mbed_itm_init(); |
63 |
| -#endif |
64 |
| -} |
65 |
| - |
66 |
| -static void fault_putc(char ch) |
67 |
| -{ |
68 |
| -#if DEVICE_SERIAL |
69 |
| - serial_putc(&stdio_uart, ch); |
70 |
| -#endif |
71 |
| - |
72 |
| -#if DEVICE_ITM |
73 |
| - /*Initialize ITM interfaces*/ |
74 |
| - mbed_itm_send(ITM_PORT_SWO, ch); |
75 |
| -#endif |
76 |
| -} |
77 |
| - |
78 |
| -/* Limited print functionality which prints the string out to |
79 |
| -stdout/uart without using stdlib by directly calling serial-api |
80 |
| -and also uses less resources |
81 |
| -The fmtstr contains the format string for printing and for every % |
82 |
| -found in that it fetches a uint32 value from values buffer |
83 |
| -and prints it in hex format. |
84 |
| -*/ |
85 |
| -static void fault_print(char *fmtstr, uint32_t *values) |
86 |
| -{ |
87 |
| -#if DEVICE_SERIAL || DEVICE_ITM |
88 |
| - int i = 0; |
89 |
| - int idx = 0; |
90 |
| - int vidx = 0; |
91 |
| - char num_str[9]={0}; |
92 |
| - char *str=NULL; |
93 |
| - |
94 |
| - //Init error reporting interfaces |
95 |
| - fault_print_init(); |
96 |
| - |
97 |
| - while(fmtstr[i] != '\0') { |
98 |
| - if(fmtstr[i]=='%') { |
99 |
| - i++; |
100 |
| - if(fmtstr[i]=='x') { |
101 |
| - //print the number in hex format |
102 |
| - value_to_hex_str(values[vidx++],num_str); |
103 |
| - for(idx=7; idx>=0; idx--) { |
104 |
| - fault_putc(num_str[idx]); |
105 |
| - } |
106 |
| - } |
107 |
| - else if(fmtstr[i]=='s') { |
108 |
| - //print the string |
109 |
| - str = (char *)((uint32_t)values[vidx++]); |
110 |
| - while(*str != '\0') { |
111 |
| - fault_putc(*str); |
112 |
| - str++; |
113 |
| - } |
114 |
| - str = NULL; |
115 |
| - } else { |
116 |
| - //Do not handle any other % formatting and keep going |
117 |
| - } |
118 |
| - } else { |
119 |
| - //handle carriage returns |
120 |
| - if (fmtstr[i] == '\n') { |
121 |
| - fault_putc('\r'); |
122 |
| - } |
123 |
| - fault_putc(fmtstr[i]); |
124 |
| - } |
125 |
| - i++; |
126 |
| - } |
127 |
| -#endif |
128 |
| -} |
129 |
| - |
130 |
| -#ifdef MBED_CONF_RTOS_PRESENT |
131 |
| -/* Prints info of a thread(using osRtxThread_t struct)*/ |
132 |
| -static void print_thread(osRtxThread_t *thread) |
133 |
| -{ |
134 |
| - uint32_t data[5]; |
135 |
| - |
136 |
| - data[0]=thread->state; |
137 |
| - data[1]=thread->thread_addr; |
138 |
| - data[2]=thread->stack_size; |
139 |
| - data[3]=(uint32_t)thread->stack_mem; |
140 |
| - data[4]=thread->sp; |
141 |
| - fault_print("\nState: 0x%x Entry: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data); |
142 |
| -} |
143 |
| - |
144 |
| -/* Prints thread info from a list */ |
145 |
| -static void print_threads_info(osRtxThread_t *threads) |
146 |
| -{ |
147 |
| - while(threads != NULL) { |
148 |
| - print_thread( threads ); |
149 |
| - threads = threads->thread_next; |
150 |
| - } |
151 |
| -} |
152 |
| - |
153 |
| -#endif |
154 |
| - |
155 | 32 | //This is a handler function called from Fault handler to print the error information out.
|
156 | 33 | //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.
|
157 |
| -__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn) |
| 34 | +void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn) |
158 | 35 | {
|
159 | 36 | mbed_error_status_t faultStatus = MBED_SUCCESS;
|
160 | 37 |
|
161 |
| - fault_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL); |
| 38 | + mbed_error_printf("\n++ MbedOS Fault Handler ++\n\nFaultType: "); |
162 | 39 |
|
163 | 40 | switch( fault_type ) {
|
164 |
| - case HARD_FAULT_EXCEPTION: |
165 |
| - fault_print("HardFault",NULL); |
166 |
| - faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION; |
167 |
| - break; |
168 | 41 | case MEMMANAGE_FAULT_EXCEPTION:
|
169 |
| - fault_print("MemManageFault",NULL); |
| 42 | + mbed_error_printf("MemManageFault"); |
170 | 43 | faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION;
|
171 | 44 | break;
|
| 45 | + |
172 | 46 | case BUS_FAULT_EXCEPTION:
|
173 |
| - fault_print("BusFault",NULL); |
| 47 | + mbed_error_printf("BusFault"); |
174 | 48 | faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION;
|
175 | 49 | break;
|
| 50 | + |
176 | 51 | case USAGE_FAULT_EXCEPTION:
|
177 |
| - fault_print("UsageFault",NULL); |
| 52 | + mbed_error_printf("UsageFault"); |
178 | 53 | faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION;
|
179 | 54 | break;
|
180 |
| - default: |
181 |
| - fault_print("Unknown Fault",NULL); |
182 |
| - faultStatus = MBED_ERROR_UNKNOWN; |
| 55 | + |
| 56 | + //There is no way we can hit this code without getting an exception, so we have the default treated like hardfault |
| 57 | + case HARD_FAULT_EXCEPTION: |
| 58 | + default: |
| 59 | + mbed_error_printf("HardFault"); |
| 60 | + faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION; |
183 | 61 | break;
|
184 | 62 | }
|
185 |
| - fault_print("\n\nContext:",NULL); |
| 63 | + mbed_error_printf("\n\nContext:"); |
186 | 64 | print_context_info();
|
187 |
| - |
188 |
| - fault_print("\n\nThreads Info:\nCurrent:",NULL); |
189 |
| - print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr); |
190 |
| - |
191 |
| - fault_print("\nNext:",NULL); |
192 |
| - print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next); |
193 |
| - |
194 |
| - fault_print("\nWait:",NULL); |
195 |
| - osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list; |
196 |
| - print_threads_info(threads); |
197 |
| - |
198 |
| - fault_print("\nDelay:",NULL); |
199 |
| - threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list; |
200 |
| - print_threads_info(threads); |
201 | 65 |
|
202 |
| - fault_print("\nIdle:",NULL); |
203 |
| - threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle; |
204 |
| - print_threads_info(threads); |
205 |
| - |
206 |
| - fault_print("\n\n-- MbedOS Fault Handler --\n\n",NULL); |
| 66 | + mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n"); |
207 | 67 |
|
208 | 68 | //Now call mbed_error, to log the error and halt the system
|
209 |
| - mbed_error( MBED_MAKE_ERROR( MBED_MODULE_UNKNOWN, faultStatus ), "System encountered an unrecoverable fault exception, halting system.", mbed_fault_context.PC_reg, NULL, 0 ); |
| 69 | + mbed_error( faultStatus, "Unrecoverable fault excaption.", mbed_fault_context.PC_reg, NULL, 0 ); |
210 | 70 |
|
211 |
| - /* In case we return, just spin here, we have already crashed */ |
212 |
| - for (;;) { |
213 |
| - __WFI(); |
214 |
| - } |
215 | 71 | }
|
216 | 72 |
|
217 |
| -void print_context_info(void) |
| 73 | +MBED_NOINLINE void print_context_info(void) |
218 | 74 | {
|
219 | 75 | //Context Regs
|
220 |
| - fault_print("\nR0 : %x" |
221 |
| - "\nR1 : %x" |
222 |
| - "\nR2 : %x" |
223 |
| - "\nR3 : %x" |
224 |
| - "\nR4 : %x" |
225 |
| - "\nR5 : %x" |
226 |
| - "\nR6 : %x" |
227 |
| - "\nR7 : %x" |
228 |
| - "\nR8 : %x" |
229 |
| - "\nR9 : %x" |
230 |
| - "\nR10 : %x" |
231 |
| - "\nR11 : %x" |
232 |
| - "\nR12 : %x" |
233 |
| - "\nSP : %x" |
234 |
| - "\nLR : %x" |
235 |
| - "\nPC : %x" |
236 |
| - "\nxPSR : %x" |
237 |
| - "\nPSP : %x" |
238 |
| - "\nMSP : %x", (uint32_t *)&mbed_fault_context); |
| 76 | + for(int i=0;i<13;i++) { |
| 77 | + mbed_error_printf("\nR%-4d: %08X", i, ((uint32_t *)&mbed_fault_context)[i]); |
| 78 | + } |
| 79 | + |
| 80 | + mbed_error_printf("\nSP : %08X" |
| 81 | + "\nLR : %08X" |
| 82 | + "\nPC : %08X" |
| 83 | + "\nxPSR : %08X" |
| 84 | + "\nPSP : %08X" |
| 85 | + "\nMSP : %08X", mbed_fault_context.SP_reg, mbed_fault_context.LR_reg, mbed_fault_context.PC_reg, |
| 86 | + mbed_fault_context.xPSR, mbed_fault_context.PSP, mbed_fault_context.MSP ); |
239 | 87 |
|
240 | 88 | //Capture CPUID to get core/cpu info
|
241 |
| - fault_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID); |
| 89 | + mbed_error_printf("\nCPUID: %08X", SCB->CPUID); |
242 | 90 |
|
243 | 91 | #if !defined(TARGET_M0) && !defined(TARGET_M0P)
|
244 | 92 | //Capture fault information registers to infer the cause of exception
|
245 |
| - uint32_t FSR[7] = {0}; |
246 |
| - |
247 |
| - FSR[0] = SCB->HFSR; |
248 |
| - //Split/Capture CFSR into MMFSR, BFSR, UFSR |
249 |
| - FSR[1] = 0xFF & SCB->CFSR;//MMFSR |
250 |
| - FSR[2] = (0xFF00 & SCB->CFSR) >> 8;//BFSR |
251 |
| - FSR[3] = (0xFFFF0000 & SCB->CFSR) >> 16;//UFSR |
252 |
| - FSR[4] = SCB->DFSR; |
253 |
| - FSR[5] = SCB->AFSR; |
254 |
| - FSR[6] = SCB->SHCSR; |
255 |
| - fault_print("\nHFSR : %x" |
256 |
| - "\nMMFSR: %x" |
257 |
| - "\nBFSR : %x" |
258 |
| - "\nUFSR : %x" |
259 |
| - "\nDFSR : %x" |
260 |
| - "\nAFSR : %x" |
261 |
| - "\nSHCSR: %x",FSR); |
| 93 | + mbed_error_printf("\nHFSR : %08X" |
| 94 | + "\nMMFSR: %08X" |
| 95 | + "\nBFSR : %08X" |
| 96 | + "\nUFSR : %08X" |
| 97 | + "\nDFSR : %08X" |
| 98 | + "\nAFSR : %08X" ////Split/Capture CFSR into MMFSR, BFSR, UFSR |
| 99 | + ,SCB->HFSR, (0xFF & SCB->CFSR), ((0xFF00 & SCB->CFSR) >> 8), ((0xFFFF0000 & SCB->CFSR) >> 16), SCB->DFSR, SCB->AFSR ); |
262 | 100 |
|
263 | 101 | //Print MMFAR only if its valid as indicated by MMFSR
|
264 |
| - if(FSR[1] & 0x80) { |
265 |
| - fault_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR); |
| 102 | + if((0xFF & SCB->CFSR) & 0x80) { |
| 103 | + mbed_error_printf("\nMMFAR: %08X",SCB->MMFAR); |
266 | 104 | }
|
267 | 105 | //Print BFAR only if its valid as indicated by BFSR
|
268 |
| - if(FSR[2] & 0x80) { |
269 |
| - fault_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR); |
| 106 | + if(((0xFF00 & SCB->CFSR) >> 8) & 0x80) { |
| 107 | + mbed_error_printf("\nBFAR : %08X",SCB->BFAR); |
270 | 108 | }
|
271 | 109 | #endif
|
| 110 | + |
272 | 111 | //Print Mode
|
273 | 112 | if(mbed_fault_context.EXC_RETURN & 0x8) {
|
274 |
| - fault_print("\nMode : Thread", NULL); |
| 113 | + mbed_error_printf("\nMode : Thread"); |
275 | 114 | //Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
|
276 | 115 | //Note that the CONTROL register captured still reflects the privilege status of the
|
277 | 116 | //thread mode eventhough we are in Handler mode by the time we capture it.
|
278 | 117 | if(mbed_fault_context.CONTROL & 0x1) {
|
279 |
| - fault_print("\nPriv : User", NULL); |
| 118 | + mbed_error_printf("\nPriv : User"); |
280 | 119 | } else {
|
281 |
| - fault_print("\nPriv : Privileged", NULL); |
| 120 | + mbed_error_printf("\nPriv : Privileged"); |
282 | 121 | }
|
283 | 122 | } else {
|
284 |
| - fault_print("\nMode : Handler", NULL); |
285 |
| - fault_print("\nPriv : Privileged", NULL); |
| 123 | + mbed_error_printf("\nMode : Handler"); |
| 124 | + mbed_error_printf("\nPriv : Privileged"); |
286 | 125 | }
|
287 | 126 | //Print Return Stack
|
288 | 127 | if(mbed_fault_context.EXC_RETURN & 0x4) {
|
289 |
| - fault_print("\nStack: PSP", NULL); |
| 128 | + mbed_error_printf("\nStack: PSP"); |
290 | 129 | } else {
|
291 |
| - fault_print("\nStack: MSP", NULL); |
| 130 | + mbed_error_printf("\nStack: MSP"); |
292 | 131 | }
|
293 | 132 | }
|
294 | 133 |
|
|
0 commit comments