Browse Source

enhancement hard fault exception handler.

aozima 12 years ago
parent
commit
ce4f0329db

+ 19 - 2
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}

+ 21 - 2
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}

+ 12 - 3
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}

+ 226 - 24
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 <rtthread.h>
@@ -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)