diff --git a/libcpu/arm/cortex-m7/context_gcc.S b/libcpu/arm/cortex-m7/context_gcc.S index 5985d54fb3..d003ce0ea0 100644 --- a/libcpu/arm/cortex-m7/context_gcc.S +++ b/libcpu/arm/cortex-m7/context_gcc.S @@ -1,7 +1,7 @@ /* * File : context_gcc.S * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2009, RT-Thread Development Team + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -13,6 +13,7 @@ * 2012-01-01 aozima support context switch load/store FPU register. * 2013-06-18 aozima add restore MSP feature. * 2013-06-23 aozima support lazy stack optimized. + * 2018-07-24 aozima enhancement hard fault exception handler. */ /** @@ -220,10 +221,29 @@ rt_hw_interrupt_thread_switch: .type HardFault_Handler, %function HardFault_Handler: /* get current context */ - MRS r0, psp /* get fault thread stack pointer */ - PUSH {lr} + MRS r0, msp /* get fault context from handler. */ + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _get_sp_done + MRS r0, psp /* get fault context from thread. */ +_get_sp_done: + + STMFD r0!, {r4 - r11} /* push r4 - r11 register */ +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + STMFD r0!, {lr} /* push dummy for flag */ +#endif + STMFD r0!, {lr} /* push exec_return register */ + + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _update_msp + MSR psp, r0 /* update stack pointer to PSP. */ + B _update_done +_update_msp: + MSR msp, r0 /* update stack pointer to MSP. */ +_update_done: + + PUSH {LR} BL rt_hw_hard_fault_exception - POP {lr} + POP {LR} ORR lr, lr, #0x04 BX lr diff --git a/libcpu/arm/cortex-m7/context_iar.S b/libcpu/arm/cortex-m7/context_iar.S index c34600ea4c..bf707d0d53 100644 --- a/libcpu/arm/cortex-m7/context_iar.S +++ b/libcpu/arm/cortex-m7/context_iar.S @@ -1,7 +1,7 @@ ;/* ; * File : context_iar.S ; * This file is part of RT-Thread RTOS -; * COPYRIGHT (C) 2009, RT-Thread Development Team +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team ; * ; * The license and distribution terms for this file may be ; * found in the file LICENSE in this distribution or at @@ -14,6 +14,7 @@ ; * 2012-01-01 aozima support context switch load/store FPU register. ; * 2013-06-18 aozima add restore MSP feature. ; * 2013-06-23 aozima support lazy stack optimized. +; * 2018-07-24 aozima enhancement hard fault exception handler. ; */ ;/** @@ -223,7 +224,29 @@ rt_hw_interrupt_thread_switch: HardFault_Handler: ; get current context - MRS r0, psp ; get fault thread stack pointer + MRS r0, msp ; get fault context from handler. + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _get_sp_done + MRS r0, psp ; get fault context from thread. +_get_sp_done + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + ;STMFD r0!, {lr} ; push exec_return register +#if defined ( __ARMVFP__ ) + SUB r0, r0, #0x04 ; push dummy for flag + STR lr, [r0] +#endif + SUB r0, r0, #0x04 + STR lr, [r0] + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _update_msp + MSR psp, r0 ; update stack pointer to PSP. + B _update_done +_update_msp + MSR msp, r0 ; update stack pointer to MSP. +_update_done + PUSH {lr} BL rt_hw_hard_fault_exception POP {lr} diff --git a/libcpu/arm/cortex-m7/context_rvds.S b/libcpu/arm/cortex-m7/context_rvds.S index dc9a958646..1abe477eab 100644 --- a/libcpu/arm/cortex-m7/context_rvds.S +++ b/libcpu/arm/cortex-m7/context_rvds.S @@ -1,7 +1,7 @@ ;/* ; * File : context_rvds.S ; * This file is part of RT-Thread RTOS -; * COPYRIGHT (C) 2009, RT-Thread Development Team +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team ; * ; * The license and distribution terms for this file may be ; * found in the file LICENSE in this distribution or at @@ -13,6 +13,7 @@ ; * 2012-01-01 aozima support context switch load/store FPU register. ; * 2013-06-18 aozima add restore MSP feature. ; * 2013-06-23 aozima support lazy stack optimized. +; * 2018-07-24 aozima enhancement hard fault exception handler. ; */ ;/** @@ -227,7 +228,22 @@ HardFault_Handler PROC MemManage_Handler ; get current context - MRS r0, psp ; get fault thread stack pointer + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler. + MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread. + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + IF {FPU} != "SoftVFP" + STMFD r0!, {lr} ; push dummy for flag + ENDIF + STMFD r0!, {lr} ; push exec_return register + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP. + MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP. + PUSH {lr} BL rt_hw_hard_fault_exception POP {lr} diff --git a/libcpu/arm/cortex-m7/cpuport.c b/libcpu/arm/cortex-m7/cpuport.c index e74c337c60..dabe4cdb93 100644 --- a/libcpu/arm/cortex-m7/cpuport.c +++ b/libcpu/arm/cortex-m7/cpuport.c @@ -1,7 +1,7 @@ /* * File : cpuport.c * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006 - 2014, RT-Thread Development Team + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -17,6 +17,7 @@ * 2012-12-23 aozima stack addr align to 8byte. * 2012-12-29 Bernard Add exception hook. * 2013-06-23 aozima support lazy stack optimized. + * 2018-07-24 aozima enhancement hard fault exception handler. */ #include @@ -177,14 +178,197 @@ rt_uint8_t *rt_hw_stack_init(void *tentry, * * @param exception_handle the exception handling hook function. */ -void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context)) +void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context)) { rt_exception_hook = exception_handle; } -void rt_hw_hard_fault_exception(struct exception_stack_frame *exception_stack) +#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */ +#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */ +#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */ +#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */ + +#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */ +#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */ +#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */ + +#ifdef RT_USING_FINSH +static void usage_fault_track(void) +{ + rt_kprintf("usage fault:\n"); + rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR); + + if(SCB_CFSR_UFSR & (1<<0)) + { + /* [0]:UNDEFINSTR */ + rt_kprintf("UNDEFINSTR "); + } + + if(SCB_CFSR_UFSR & (1<<1)) + { + /* [1]:INVSTATE */ + rt_kprintf("INVSTATE "); + } + + if(SCB_CFSR_UFSR & (1<<2)) + { + /* [2]:INVPC */ + rt_kprintf("INVPC "); + } + + if(SCB_CFSR_UFSR & (1<<3)) + { + /* [3]:NOCP */ + rt_kprintf("NOCP "); + } + + if(SCB_CFSR_UFSR & (1<<8)) + { + /* [8]:UNALIGNED */ + rt_kprintf("UNALIGNED "); + } + + if(SCB_CFSR_UFSR & (1<<9)) + { + /* [9]:DIVBYZERO */ + rt_kprintf("DIVBYZERO "); + } + + rt_kprintf("\n"); +} + +static void bus_fault_track(void) +{ + rt_kprintf("bus fault:\n"); + rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR); + + if(SCB_CFSR_BFSR & (1<<0)) + { + /* [0]:IBUSERR */ + rt_kprintf("IBUSERR "); + } + + if(SCB_CFSR_BFSR & (1<<1)) + { + /* [1]:PRECISERR */ + rt_kprintf("PRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<2)) + { + /* [2]:IMPRECISERR */ + rt_kprintf("IMPRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<3)) + { + /* [3]:UNSTKERR */ + rt_kprintf("UNSTKERR "); + } + + if(SCB_CFSR_BFSR & (1<<4)) + { + /* [4]:STKERR */ + rt_kprintf("STKERR "); + } + + if(SCB_CFSR_BFSR & (1<<7)) + { + rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void mem_manage_fault_track(void) +{ + rt_kprintf("mem manage fault:\n"); + rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR); + + if(SCB_CFSR_MFSR & (1<<0)) + { + /* [0]:IACCVIOL */ + rt_kprintf("IACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<1)) + { + /* [1]:DACCVIOL */ + rt_kprintf("DACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<3)) + { + /* [3]:MUNSTKERR */ + rt_kprintf("MUNSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<4)) + { + /* [4]:MSTKERR */ + rt_kprintf("MSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<7)) + { + /* [7]:MMARVALID */ + rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void hard_fault_track(void) +{ + if(SCB_HFSR & (1UL<<1)) + { + /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */ + rt_kprintf("failed vector fetch\n"); + } + + if(SCB_HFSR & (1UL<<30)) + { + /* [30]:FORCED, Indicates hard fault is taken because of bus fault, + memory management fault, or usage fault. */ + if(SCB_CFSR_BFSR) + { + bus_fault_track(); + } + + if(SCB_CFSR_MFSR) + { + mem_manage_fault_track(); + } + + if(SCB_CFSR_UFSR) + { + usage_fault_track(); + } + } + + if(SCB_HFSR & (1UL<<31)) + { + /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */ + rt_kprintf("debug event\n"); + } +} +#endif /* RT_USING_FINSH */ + +struct exception_info +{ + rt_uint32_t exc_return; + struct stack_frame stack_frame; +}; + +void rt_hw_hard_fault_exception(struct exception_info *exception_info) { extern long list_thread(void); + struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame; + struct stack_frame *context = &exception_info->stack_frame; if (rt_exception_hook != RT_NULL) { @@ -194,20 +378,45 @@ void rt_hw_hard_fault_exception(struct exception_stack_frame *exception_stack) if (result == RT_EOK) return; } - rt_kprintf("psr: 0x%08x\n", exception_stack->psr); - rt_kprintf(" pc: 0x%08x\n", exception_stack->pc); - rt_kprintf(" lr: 0x%08x\n", exception_stack->lr); - rt_kprintf("r12: 0x%08x\n", exception_stack->r12); - rt_kprintf("r03: 0x%08x\n", exception_stack->r3); - rt_kprintf("r02: 0x%08x\n", exception_stack->r2); - rt_kprintf("r01: 0x%08x\n", exception_stack->r1); - rt_kprintf("r00: 0x%08x\n", exception_stack->r0); + rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); - rt_kprintf("hard fault on thread: %s\n", rt_thread_self()->name); + rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); + rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); + rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); + rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); + rt_kprintf("r04: 0x%08x\n", context->r4); + rt_kprintf("r05: 0x%08x\n", context->r5); + rt_kprintf("r06: 0x%08x\n", context->r6); + rt_kprintf("r07: 0x%08x\n", context->r7); + rt_kprintf("r08: 0x%08x\n", context->r8); + rt_kprintf("r09: 0x%08x\n", context->r9); + rt_kprintf("r10: 0x%08x\n", context->r10); + rt_kprintf("r11: 0x%08x\n", context->r11); + rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); + rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); + rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); + + if (exception_info->exc_return & (1 << 2)) + { + rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); #ifdef RT_USING_FINSH - list_thread(); + list_thread(); #endif + } + else + { + rt_kprintf("hard fault on handler\r\n\r\n"); + } + + if ( (exception_info->exc_return & 0x10) == 0) + { + rt_kprintf("FPU active!\r\n"); + } + +#ifdef RT_USING_FINSH + hard_fault_track(); +#endif /* RT_USING_FINSH */ while (1); }