浏览代码

[libcpu][comtex-m7] enhancement hard fault exception handler.

aozima 6 年之前
父节点
当前提交
d431f4b5f9
共有 4 个文件被更改,包括 290 次插入22 次删除
  1. 24 4
      libcpu/arm/cortex-m7/context_gcc.S
  2. 25 2
      libcpu/arm/cortex-m7/context_iar.S
  3. 18 2
      libcpu/arm/cortex-m7/context_rvds.S
  4. 223 14
      libcpu/arm/cortex-m7/cpuport.c

+ 24 - 4
libcpu/arm/cortex-m7/context_gcc.S

@@ -1,7 +1,7 @@
 /*
 /*
  * File      : context_gcc.S
  * File      : context_gcc.S
  * This file is part of RT-Thread RTOS
  * 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
  * The license and distribution terms for this file may be
  * found in the file LICENSE in this distribution or at
  * 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.
  * 2012-01-01     aozima       support context switch load/store FPU register.
  * 2013-06-18     aozima       add restore MSP feature.
  * 2013-06-18     aozima       add restore MSP feature.
  * 2013-06-23     aozima       support lazy stack optimized.
  * 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
 .type HardFault_Handler, %function
 HardFault_Handler:
 HardFault_Handler:
     /* get current context */
     /* 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
     BL      rt_hw_hard_fault_exception
-    POP     {lr}
+    POP     {LR}
 
 
     ORR     lr, lr, #0x04
     ORR     lr, lr, #0x04
     BX      lr
     BX      lr

+ 25 - 2
libcpu/arm/cortex-m7/context_iar.S

@@ -1,7 +1,7 @@
 ;/*
 ;/*
 ; * File      : context_iar.S
 ; * File      : context_iar.S
 ; * This file is part of RT-Thread RTOS
 ; * 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
 ; * The license and distribution terms for this file may be
 ; * found in the file LICENSE in this distribution or at
 ; * 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.
 ; * 2012-01-01     aozima       support context switch load/store FPU register.
 ; * 2013-06-18     aozima       add restore MSP feature.
 ; * 2013-06-18     aozima       add restore MSP feature.
 ; * 2013-06-23     aozima       support lazy stack optimized.
 ; * 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:
 HardFault_Handler:
 
 
     ; get current context
     ; 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}
     PUSH    {lr}
     BL      rt_hw_hard_fault_exception
     BL      rt_hw_hard_fault_exception
     POP     {lr}
     POP     {lr}

+ 18 - 2
libcpu/arm/cortex-m7/context_rvds.S

@@ -1,7 +1,7 @@
 ;/*
 ;/*
 ; * File      : context_rvds.S
 ; * File      : context_rvds.S
 ; * This file is part of RT-Thread RTOS
 ; * 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
 ; * The license and distribution terms for this file may be
 ; * found in the file LICENSE in this distribution or at
 ; * 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.
 ; * 2012-01-01     aozima       support context switch load/store FPU register.
 ; * 2013-06-18     aozima       add restore MSP feature.
 ; * 2013-06-18     aozima       add restore MSP feature.
 ; * 2013-06-23     aozima       support lazy stack optimized.
 ; * 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
 MemManage_Handler
 
 
     ; get current context
     ; 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}
     PUSH    {lr}
     BL      rt_hw_hard_fault_exception
     BL      rt_hw_hard_fault_exception
     POP     {lr}
     POP     {lr}

+ 223 - 14
libcpu/arm/cortex-m7/cpuport.c

@@ -1,7 +1,7 @@
 /*
 /*
  * File      : cpuport.c
  * File      : cpuport.c
  * This file is part of RT-Thread RTOS
  * 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
  * The license and distribution terms for this file may be
  * found in the file LICENSE in this distribution or at
  * 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-23     aozima       stack addr align to 8byte.
  * 2012-12-29     Bernard      Add exception hook.
  * 2012-12-29     Bernard      Add exception hook.
  * 2013-06-23     aozima       support lazy stack optimized.
  * 2013-06-23     aozima       support lazy stack optimized.
+ * 2018-07-24     aozima       enhancement hard fault exception handler.
  */
  */
 
 
 #include <rtthread.h>
 #include <rtthread.h>
@@ -177,14 +178,197 @@ rt_uint8_t *rt_hw_stack_init(void       *tentry,
  *
  *
  * @param exception_handle the exception handling hook function.
  * @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;
     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);
     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)
     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;
         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("hard fault on thread: %s\n", rt_thread_self()->name);
+    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);
+
+    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
 #ifdef RT_USING_FINSH
-    list_thread();
+        list_thread();
 #endif
 #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);
     while (1);
 }
 }