1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2009-01-05 Bernard first version 9 * 2011-02-14 onelife Modify for EFM32 10 * 2011-06-17 onelife Merge all of the C source code into cpuport.c 11 * 2012-12-23 aozima stack addr align to 8byte. 12 * 2012-12-29 Bernard Add exception hook. 13 * 2013-07-09 aozima enhancement hard fault exception handler. 14 */ 15 16 #include <rtthread.h> 17 18 struct exception_stack_frame 19 { 20 rt_uint32_t r0; 21 rt_uint32_t r1; 22 rt_uint32_t r2; 23 rt_uint32_t r3; 24 rt_uint32_t r12; 25 rt_uint32_t lr; 26 rt_uint32_t pc; 27 rt_uint32_t psr; 28 }; 29 30 struct stack_frame 31 { 32 /* r4 ~ r11 register */ 33 rt_uint32_t r4; 34 rt_uint32_t r5; 35 rt_uint32_t r6; 36 rt_uint32_t r7; 37 rt_uint32_t r8; 38 rt_uint32_t r9; 39 rt_uint32_t r10; 40 rt_uint32_t r11; 41 42 struct exception_stack_frame exception_stack_frame; 43 }; 44 45 /* flag in interrupt handling */ 46 rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; 47 rt_uint32_t rt_thread_switch_interrupt_flag; 48 /* exception hook */ 49 static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL; 50 51 /** 52 * This function will initialize thread stack 53 * 54 * @param tentry the entry of thread 55 * @param parameter the parameter of entry 56 * @param stack_addr the beginning stack address 57 * @param texit the function will be called when thread exit 58 * 59 * @return stack address 60 */ 61 rt_uint8_t *rt_hw_stack_init(void *tentry, 62 void *parameter, 63 rt_uint8_t *stack_addr, 64 void *texit) 65 { 66 struct stack_frame *stack_frame; 67 rt_uint8_t *stk; 68 unsigned long i; 69 70 stk = stack_addr + sizeof(rt_uint32_t); 71 stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); 72 stk -= sizeof(struct stack_frame); 73 74 stack_frame = (struct stack_frame *)stk; 75 76 /* init all register */ 77 for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++) 78 { 79 ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef; 80 } 81 82 stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ 83 stack_frame->exception_stack_frame.r1 = 0; /* r1 */ 84 stack_frame->exception_stack_frame.r2 = 0; /* r2 */ 85 stack_frame->exception_stack_frame.r3 = 0; /* r3 */ 86 stack_frame->exception_stack_frame.r12 = 0; /* r12 */ 87 stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */ 88 stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ 89 stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ 90 91 /* return task's current stack address */ 92 return stk; 93 } 94 95 /** 96 * This function set the hook, which is invoked on fault exception handling. 97 * 98 * @param exception_handle the exception handling hook function. 99 */ 100 void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context)) 101 { 102 rt_exception_hook = exception_handle; 103 } 104 105 #define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */ 106 #define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */ 107 #define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */ 108 #define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */ 109 #define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */ 110 #define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */ 111 112 #define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */ 113 #define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */ 114 #define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */ 115 116 #ifdef RT_USING_FINSH 117 static void usage_fault_track(void) 118 { 119 rt_kprintf("usage fault:\n"); 120 rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR); 121 122 if(SCB_CFSR_UFSR & (1<<0)) 123 { 124 /* [0]:UNDEFINSTR */ 125 rt_kprintf("UNDEFINSTR "); 126 } 127 128 if(SCB_CFSR_UFSR & (1<<1)) 129 { 130 /* [1]:INVSTATE */ 131 rt_kprintf("INVSTATE "); 132 } 133 134 if(SCB_CFSR_UFSR & (1<<2)) 135 { 136 /* [2]:INVPC */ 137 rt_kprintf("INVPC "); 138 } 139 140 if(SCB_CFSR_UFSR & (1<<3)) 141 { 142 /* [3]:NOCP */ 143 rt_kprintf("NOCP "); 144 } 145 146 if(SCB_CFSR_UFSR & (1<<8)) 147 { 148 /* [8]:UNALIGNED */ 149 rt_kprintf("UNALIGNED "); 150 } 151 152 if(SCB_CFSR_UFSR & (1<<9)) 153 { 154 /* [9]:DIVBYZERO */ 155 rt_kprintf("DIVBYZERO "); 156 } 157 158 rt_kprintf("\n"); 159 } 160 161 static void bus_fault_track(void) 162 { 163 rt_kprintf("bus fault:\n"); 164 rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR); 165 166 if(SCB_CFSR_BFSR & (1<<0)) 167 { 168 /* [0]:IBUSERR */ 169 rt_kprintf("IBUSERR "); 170 } 171 172 if(SCB_CFSR_BFSR & (1<<1)) 173 { 174 /* [1]:PRECISERR */ 175 rt_kprintf("PRECISERR "); 176 } 177 178 if(SCB_CFSR_BFSR & (1<<2)) 179 { 180 /* [2]:IMPRECISERR */ 181 rt_kprintf("IMPRECISERR "); 182 } 183 184 if(SCB_CFSR_BFSR & (1<<3)) 185 { 186 /* [3]:UNSTKERR */ 187 rt_kprintf("UNSTKERR "); 188 } 189 190 if(SCB_CFSR_BFSR & (1<<4)) 191 { 192 /* [4]:STKERR */ 193 rt_kprintf("STKERR "); 194 } 195 196 if(SCB_CFSR_BFSR & (1<<7)) 197 { 198 rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR); 199 } 200 else 201 { 202 rt_kprintf("\n"); 203 } 204 } 205 206 static void mem_manage_fault_track(void) 207 { 208 rt_kprintf("mem manage fault:\n"); 209 rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR); 210 211 if(SCB_CFSR_MFSR & (1<<0)) 212 { 213 /* [0]:IACCVIOL */ 214 rt_kprintf("IACCVIOL "); 215 } 216 217 if(SCB_CFSR_MFSR & (1<<1)) 218 { 219 /* [1]:DACCVIOL */ 220 rt_kprintf("DACCVIOL "); 221 } 222 223 if(SCB_CFSR_MFSR & (1<<3)) 224 { 225 /* [3]:MUNSTKERR */ 226 rt_kprintf("MUNSTKERR "); 227 } 228 229 if(SCB_CFSR_MFSR & (1<<4)) 230 { 231 /* [4]:MSTKERR */ 232 rt_kprintf("MSTKERR "); 233 } 234 235 if(SCB_CFSR_MFSR & (1<<7)) 236 { 237 /* [7]:MMARVALID */ 238 rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR); 239 } 240 else 241 { 242 rt_kprintf("\n"); 243 } 244 } 245 246 static void hard_fault_track(void) 247 { 248 if(SCB_HFSR & (1UL<<1)) 249 { 250 /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */ 251 rt_kprintf("failed vector fetch\n"); 252 } 253 254 if(SCB_HFSR & (1UL<<30)) 255 { 256 /* [30]:FORCED, Indicates hard fault is taken because of bus fault, 257 memory management fault, or usage fault. */ 258 if(SCB_CFSR_BFSR) 259 { 260 bus_fault_track(); 261 } 262 263 if(SCB_CFSR_MFSR) 264 { 265 mem_manage_fault_track(); 266 } 267 268 if(SCB_CFSR_UFSR) 269 { 270 usage_fault_track(); 271 } 272 } 273 274 if(SCB_HFSR & (1UL<<31)) 275 { 276 /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */ 277 rt_kprintf("debug event\n"); 278 } 279 } 280 #endif /* RT_USING_FINSH */ 281 282 struct exception_info 283 { 284 rt_uint32_t exc_return; 285 struct stack_frame stack_frame; 286 }; 287 288 /* 289 * fault exception handler 290 */ 291 void rt_hw_hard_fault_exception(struct exception_info * exception_info) 292 { 293 extern long list_thread(void); 294 struct stack_frame* context = &exception_info->stack_frame; 295 296 if (rt_exception_hook != RT_NULL) 297 { 298 rt_err_t result; 299 300 result = rt_exception_hook(exception_info); 301 if (result == RT_EOK) 302 return; 303 } 304 305 rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); 306 307 rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); 308 rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); 309 rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); 310 rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); 311 rt_kprintf("r04: 0x%08x\n", context->r4); 312 rt_kprintf("r05: 0x%08x\n", context->r5); 313 rt_kprintf("r06: 0x%08x\n", context->r6); 314 rt_kprintf("r07: 0x%08x\n", context->r7); 315 rt_kprintf("r08: 0x%08x\n", context->r8); 316 rt_kprintf("r09: 0x%08x\n", context->r9); 317 rt_kprintf("r10: 0x%08x\n", context->r10); 318 rt_kprintf("r11: 0x%08x\n", context->r11); 319 rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); 320 rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); 321 rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); 322 323 if(exception_info->exc_return & (1 << 2) ) 324 { 325 rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); 326 327 #ifdef RT_USING_FINSH 328 list_thread(); 329 #endif /* RT_USING_FINSH */ 330 } 331 else 332 { 333 rt_kprintf("hard fault on handler\r\n\r\n"); 334 } 335 336 #ifdef RT_USING_FINSH 337 hard_fault_track(); 338 #endif /* RT_USING_FINSH */ 339 340 while (1); 341 } 342 343 /** 344 * shutdown CPU 345 */ 346 void rt_hw_cpu_shutdown(void) 347 { 348 rt_kprintf("shutdown...\n"); 349 350 RT_ASSERT(0); 351 } 352 353 /** 354 * reset CPU 355 */ 356 RT_WEAK void rt_hw_cpu_reset(void) 357 { 358 SCB_AIRCR = SCB_RESET_VALUE; 359 } 360 361 #ifdef RT_USING_CPU_FFS 362 /** 363 * This function finds the first bit set (beginning with the least significant bit) 364 * in value and return the index of that bit. 365 * 366 * Bits are numbered starting at 1 (the least significant bit). A return value of 367 * zero from any of these functions means that the argument was zero. 368 * 369 * @return return the index of the first bit set. If value is 0, then this function 370 * shall return 0. 371 */ 372 #if defined(__CC_ARM) 373 __asm int __rt_ffs(int value) 374 { 375 CMP r0, #0x00 376 BEQ exit 377 378 RBIT r0, r0 379 CLZ r0, r0 380 ADDS r0, r0, #0x01 381 382 exit 383 BX lr 384 } 385 #elif defined(__IAR_SYSTEMS_ICC__) 386 int __rt_ffs(int value) 387 { 388 if (value == 0) return value; 389 390 asm("RBIT %0, %1" : "=r"(value) : "r"(value)); 391 asm("CLZ %0, %1" : "=r"(value) : "r"(value)); 392 asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value)); 393 394 return value; 395 } 396 #elif defined(__GNUC__) 397 int __rt_ffs(int value) 398 { 399 return __builtin_ffs(value); 400 } 401 #endif 402 403 #endif 404