]> git.sur5r.net Git - freertos/commitdiff
Add workaround to XMC4000 silicon bug to Tasking Cortex-M4F port layer.
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Mon, 14 Oct 2013 14:03:05 +0000 (14:03 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Mon, 14 Oct 2013 14:03:05 +0000 (14:03 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2063 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c
FreeRTOS/Source/portable/Tasking/ARM_CM4F/port_asm.asm
FreeRTOS/Source/portable/Tasking/ARM_CM4F/portmacro.h

index d167e4a1525dee934b4158ae31cb693017d79784..c070c5c5cbaaa047d5d6e0a68aff699367d6699d 100644 (file)
 #define portINITIAL_XPSR                       ( 0x01000000 )\r
 #define portINITIAL_EXEC_RETURN                ( 0xfffffffd )\r
 \r
+/* Let the user override the pre-loading of the initial LR with the address of\r
+prvTaskExitError() in case is messes up unwinding of the stack in the\r
+debugger. */\r
+#ifdef configTASK_RETURN_ADDRESS\r
+       #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS\r
+#else\r
+       #define portTASK_RETURN_ADDRESS prvTaskExitError\r
+#endif\r
+\r
 /* The priority used by the kernel is assigned to a variable to make access\r
 from inline assembler easier. */\r
 const unsigned long ulKernelPriority = configKERNEL_INTERRUPT_PRIORITY;\r
@@ -112,6 +121,11 @@ void SysTick_Handler( void );
 extern void vPortEnableVFP( void );\r
 extern void vPortStartFirstTask( void );\r
 \r
+/*\r
+ * Used to catch tasks that attempt to return from their implementing function.\r
+ */\r
+static void prvTaskExitError( void );\r
+\r
 /* This exists purely to allow the const to be used from within the\r
 port_asm.asm assembly file. */\r
 const unsigned long ulMaxSyscallInterruptPriorityConst = configMAX_SYSCALL_INTERRUPT_PRIORITY;\r
@@ -134,7 +148,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE
        pxTopOfStack--;\r
        *pxTopOfStack = ( portSTACK_TYPE ) pxCode;      /* PC */\r
        pxTopOfStack--;\r
-       *pxTopOfStack = 0;      /* LR */\r
+       *pxTopOfStack = ( portSTACK_TYPE ) portTASK_RETURN_ADDRESS;     /* LR */\r
 \r
        /* Save code space by skipping register initialisation. */\r
        pxTopOfStack -= 5;      /* R12, R3, R2 and R1. */\r
@@ -151,6 +165,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE
 }\r
 /*-----------------------------------------------------------*/\r
 \r
+static void prvTaskExitError( void )\r
+{\r
+       /* A function that implements a task must not exit or attempt to return to\r
+       its caller as there is nothing to return to.  If a task wants to exit it \r
+       should instead call vTaskDelete( NULL ).\r
+       \r
+       Artificially force an assert() to be triggered if configASSERT() is \r
+       defined, then stop here so application writers can catch the error. */\r
+       configASSERT( ulCriticalNesting == ~0UL );\r
+       portDISABLE_INTERRUPTS();       \r
+       for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
 /*\r
  * See header file for description.\r
  */\r
index 413de2e1c598d2c5ac77c10bc082b621f177b133..93ff212856542d5c64d9401f2730fbf9c9f79f11 100644 (file)
 ;    licensing and training services.\r
 ;*/\r
 \r
+\r
        .extern pxCurrentTCB\r
        .extern vTaskSwitchContext\r
        .extern ulMaxSyscallInterruptPriorityConst\r
 \r
-       .global PendSV_Handler\r
+       .global _vector_14\r
+       .global _lc_ref__vector_pp_14\r
        .global SVC_Handler\r
        .global vPortStartFirstTask\r
        .global vPortEnableVFP\r
+       .global ulPortSetInterruptMask\r
+       .global vPortClearInterruptMask\r
        \r
 ;-----------------------------------------------------------\r
 \r
        .section .text\r
        .thumb\r
        .align 4\r
-PendSV_Handler: .type func\r
+_vector_14: .type func\r
+\r
        mrs r0, psp\r
 \r
        ;Get the location of the current TCB.\r
@@ -106,7 +111,60 @@ PendSV_Handler: .type func
        msr psp, r0\r
        bx r14\r
 \r
-       .size   PendSV_Handler, $-PendSV_Handler\r
+       .size   _vector_14, $-_vector_14\r
+       .endsec\r
+\r
+;-----------------------------------------------------------\r
+\r
+; This function is an XMC4000 silicon errata workaround.  It will get used when\r
+; the SILICON_BUG_PMC_CM_001 linker macro is defined.\r
+       .section .text\r
+       .thumb\r
+       .align 4\r
+_lc_ref__vector_pp_14: .type func\r
+\r
+       mrs r0, psp\r
+\r
+       ;Get the location of the current TCB.\r
+       ldr.w   r3, =pxCurrentTCB\r
+       ldr     r2, [r3]\r
+\r
+       ;Is the task using the FPU context?  If so, push high vfp registers.\r
+       tst r14, #0x10\r
+       it eq\r
+       vstmdbeq r0!, {s16-s31}\r
+\r
+       ;Save the core registers.\r
+       stmdb r0!, {r4-r11, r14}\r
+\r
+       ;Save the new top of stack into the first member of the TCB.\r
+       str r0, [r2]\r
+\r
+       stmdb sp!, {r3, r14}\r
+       ldr.w r0, =ulMaxSyscallInterruptPriorityConst\r
+       msr basepri, r0\r
+       bl vTaskSwitchContext\r
+       mov r0, #0\r
+       msr basepri, r0\r
+       ldmia sp!, {r3, r14}\r
+\r
+       ;The first item in pxCurrentTCB is the task top of stack.\r
+       ldr r1, [r3]\r
+       ldr r0, [r1]\r
+\r
+       ;Pop the core registers.\r
+       ldmia r0!, {r4-r11, r14}\r
+\r
+       ;Is the task using the FPU context?  If so, pop the high vfp registers too.\r
+       tst r14, #0x10\r
+       it eq\r
+       vldmiaeq r0!, {s16-s31}\r
+\r
+       msr psp, r0\r
+       push { lr }\r
+       pop { pc } ; XMC4000 specific errata workaround.  Do not used "bx lr" here.\r
+\r
+       .size   _lc_ref__vector_pp_14, $-_lc_ref__vector_pp_14\r
        .endsec\r
 \r
 ;-----------------------------------------------------------\r
@@ -163,6 +221,31 @@ vPortEnableVFP .type func
        .size   vPortEnableVFP, $-vPortEnableVFP\r
        .endsec\r
 \r
+;-----------------------------------------------------------\r
+\r
+       .section .text\r
+       .thumb\r
+       .align 4\r
+ulPortSetInterruptMask:\r
+       mrs r0, basepri\r
+       ldr.w r1, =ulMaxSyscallInterruptPriorityConst\r
+       msr basepri, r1\r
+       bx r14\r
+       .size   ulPortSetInterruptMask, $-ulPortSetInterruptMask\r
+       .endsec\r
+\r
+;-----------------------------------------------------------\r
+\r
+       .section .text\r
+       .thumb\r
+       .align 4\r
+vPortClearInterruptMask:\r
+       msr basepri, r0\r
+       bx r14\r
+       .size   vPortClearInterruptMask, $-vPortClearInterruptMask\r
+       .endsec\r
+\r
+;-----------------------------------------------------------\r
 \r
        .end\r
        \r
index 45ac21cb024fc10f68d7f411fedbee99fad102ec..a49f5eb6b2b9db0e2edd1e95f7decf578260eb00 100644 (file)
@@ -131,10 +131,10 @@ extern void vPortYield( void );
  */\r
 #define portCLEAR_INTERRUPT_MASK() __set_BASEPRI( 0 )\r
 \r
-/* FAQ:  Setting BASEPRI to 0 is not a bug.  Please see\r
-http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */\r
-#define portSET_INTERRUPT_MASK_FROM_ISR()              0;portSET_INTERRUPT_MASK()\r
-#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)   portCLEAR_INTERRUPT_MASK();(void)x\r
+extern unsigned long ulPortSetInterruptMask( void );\r
+extern void vPortClearInterruptMask( unsigned long ulNewMask );\r
+#define portSET_INTERRUPT_MASK_FROM_ISR()              ulPortSetInterruptMask()\r
+#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)   vPortClearInterruptMask( x )\r
 \r
 \r
 extern void vPortEnterCritical( void );\r