From ce4f0329dbb3bd2447be7ff588a65b76eac93801 Mon Sep 17 00:00:00 2001 From: aozima Date: Tue, 9 Jul 2013 21:40:20 +0800 Subject: [PATCH] enhancement hard fault exception handler. --- libcpu/arm/cortex-m3/context_gcc.S | 21 ++- libcpu/arm/cortex-m3/context_iar.S | 23 ++- libcpu/arm/cortex-m3/context_rvds.S | 15 +- libcpu/arm/cortex-m3/cpuport.c | 250 +++++++++++++++++++++++++--- 4 files changed, 278 insertions(+), 31 deletions(-) diff --git a/libcpu/arm/cortex-m3/context_gcc.S b/libcpu/arm/cortex-m3/context_gcc.S index c36ca9a7c3..7ff810d534 100644 --- a/libcpu/arm/cortex-m3/context_gcc.S +++ b/libcpu/arm/cortex-m3/context_gcc.S @@ -1,7 +1,7 @@ /* * File : context_gcc.S * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2009 - 2011, RT-Thread Development Team + * COPYRIGHT (C) 2006 - 2013, 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 @@ * 2011-06-17 onelife Merge all of the assembly source code into context_gcc.S * 2011-07-12 onelife Add interrupt context check function * 2013-06-18 aozima add restore MSP feature. + * 2013-07-09 aozima enhancement hard fault exception handler. */ .cpu cortex-m3 @@ -176,7 +177,23 @@ rt_hw_interrupt_thread_switch: .type HardFault_Handler, %function 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 */ + + 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-m3/context_iar.S b/libcpu/arm/cortex-m3/context_iar.S index c27f02b512..7dc595f6c1 100644 --- a/libcpu/arm/cortex-m3/context_iar.S +++ b/libcpu/arm/cortex-m3/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 - 2013, RT-Thread Development Team ; * ; * The license and distribution terms for this file may be ; * found in the file LICENSE in this distribution or at @@ -12,6 +12,7 @@ ; * 2009-01-17 Bernard first version ; * 2009-09-27 Bernard add protect when contex switch occurs ; * 2013-06-18 aozima add restore MSP feature. +; * 2013-07-09 aozima enhancement hard fault exception handler. ; */ ;/** @@ -174,7 +175,25 @@ 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 + 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-m3/context_rvds.S b/libcpu/arm/cortex-m3/context_rvds.S index 8b40c7cc48..7f431cc042 100644 --- a/libcpu/arm/cortex-m3/context_rvds.S +++ b/libcpu/arm/cortex-m3/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 - 2013, RT-Thread Development Team ; * ; * The license and distribution terms for this file may be ; * found in the file LICENSE in this distribution or at @@ -11,6 +11,7 @@ ; * Date Author Notes ; * 2009-01-17 Bernard first version ; * 2013-06-18 aozima add restore MSP feature. +; * 2013-07-09 aozima enhancement hard fault exception handler. ; */ ;/** @@ -164,7 +165,6 @@ rt_hw_context_switch_to PROC LDR r0, =SCB_VTOR LDR r0, [r0] LDR r0, [r0] - NOP MSR msp, r0 ; enable interrupts at processor level @@ -185,7 +185,16 @@ rt_hw_interrupt_thread_switch PROC HardFault_Handler PROC ; get current context - MRS r0, psp ; get fault thread stack pointer + TST lr, #0x04 ; if(!EXC_RETURN[2]) + MRSNE r0, msp ; get fault context from handler. + MRSEQ r0, psp ; get fault context from thread. + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + STMFD r0!, {lr} ; push exec_return register + + MSRNE msp, r0 ; update stack pointer to MSP. + MSREQ psp, r0 ; update stack pointer to PSP. + PUSH {lr} BL rt_hw_hard_fault_exception POP {lr} diff --git a/libcpu/arm/cortex-m3/cpuport.c b/libcpu/arm/cortex-m3/cpuport.c index b4dcad2e16..f938bab800 100644 --- a/libcpu/arm/cortex-m3/cpuport.c +++ b/libcpu/arm/cortex-m3/cpuport.c @@ -1,7 +1,7 @@ /* * File : cpuport.c * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * COPYRIGHT (C) 2006 - 2013, 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 @@ * 2011-06-17 onelife Merge all of the C source code into cpuport.c * 2012-12-23 aozima stack addr align to 8byte. * 2012-12-29 Bernard Add exception hook. + * 2013-07-09 aozima enhancement hard fault exception handler. */ #include @@ -105,39 +106,240 @@ void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context)) rt_exception_hook = exception_handle; } +#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; +}; + /* * fault exception handler */ -void rt_hw_hard_fault_exception(struct exception_stack_frame* context) +void rt_hw_hard_fault_exception(struct exception_info * exception_info) { extern long list_thread(void); + struct stack_frame* context = &exception_info->stack_frame; if (rt_exception_hook != RT_NULL) { rt_err_t result; - result = rt_exception_hook(context); + result = rt_exception_hook(exception_info); if (result == RT_EOK) return; } - rt_kprintf("psr: 0x%08x\n", context->psr); - rt_kprintf(" pc: 0x%08x\n", context->pc); - rt_kprintf(" lr: 0x%08x\n", context->lr); - rt_kprintf("r12: 0x%08x\n", context->r12); - rt_kprintf("r03: 0x%08x\n", context->r3); - rt_kprintf("r02: 0x%08x\n", context->r2); - rt_kprintf("r01: 0x%08x\n", context->r1); - rt_kprintf("r00: 0x%08x\n", context->r0); + rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); + + 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); - rt_kprintf("hard fault on thread: %s\n", rt_thread_self()->name); + 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(); -#endif + list_thread(); +#endif /* RT_USING_FINSH */ + } + else + { + rt_kprintf("hard fault on handler\r\n\r\n"); + } - while (1) - ; +#ifdef RT_USING_FINSH + hard_fault_track(); +#endif /* RT_USING_FINSH */ + + while (1); } /** @@ -152,13 +354,13 @@ void rt_hw_cpu_shutdown(void) #ifdef RT_USING_CPU_FFS /** - * This function finds the first bit set (beginning with the least significant bit) + * This function finds the first bit set (beginning with the least significant bit) * in value and return the index of that bit. * - * Bits are numbered starting at 1 (the least significant bit). A return value of + * Bits are numbered starting at 1 (the least significant bit). A return value of * zero from any of these functions means that the argument was zero. - * - * @return return the index of the first bit set. If value is 0, then this function + * + * @return return the index of the first bit set. If value is 0, then this function * shall return 0. */ #if defined(__CC_ARM) @@ -170,8 +372,8 @@ __asm int __rt_ffs(int value) CLZ r0, r0 ADDS r0, r0, #0x01 -exit - BX lr + exit + BX lr } #elif defined(__IAR_SYSTEMS_ICC__) int __rt_ffs(int value) @@ -179,8 +381,8 @@ int __rt_ffs(int value) if (value == 0) return value; __ASM("RBIT r0, r0"); - __ASM("CLZ r0, r0"); - __ASM("ADDS r0, r0, #0x01"); + __ASM("CLZ r0, r0"); + __ASM("ADDS r0, r0, #0x01"); } #elif defined(__GNUC__) int __rt_ffs(int value) -- GitLab