From fb561a0a4a30f530d549ae0c619ff8fa59d06ed4 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Tue, 8 Oct 2013 11:30:40 +0000 Subject: [PATCH] Introduce the prvTaskExitError() function for all ARM_CMn ports. Introduce the configTASK_RETURN_ADDRESS macro for the GCC ARM_CMn ports. Improve time slippage penalty when entering tickless mode is abandoned. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2056 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/portable/GCC/ARM_CM0/port.c | 11 +++- FreeRTOS/Source/portable/GCC/ARM_CM3/port.c | 38 +++++++++++++- FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c | 50 +++++++++++++++++-- FreeRTOS/Source/portable/IAR/ARM_CM3/port.c | 31 +++++++++++- .../Source/portable/IAR/ARM_CM4F/portasm.s | 48 ++++++++++-------- FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c | 30 ++++++++++- FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c | 38 +++++++++++++- 7 files changed, 217 insertions(+), 29 deletions(-) diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c index 5aef176cf..acbe363bd 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c @@ -86,6 +86,15 @@ /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case is messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + /* Each task maintains its own interrupt status in the critical nesting variable. */ static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; @@ -126,7 +135,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = ( portSTACK_TYPE ) prvTaskExitError; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) portTASK_RETURN_ADDRESS; /* LR */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ pxTopOfStack -= 8; /* R11..R4. */ diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c index 741fb64b5..ed7b4e5e1 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -118,6 +118,15 @@ occurred while the SysTick counter is stopped during tickless idle calculations. */ #define portMISSED_COUNTS_FACTOR ( 45UL ) +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case is messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + /* Each task maintains its own interrupt status in the critical nesting variable. */ static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; @@ -141,6 +150,11 @@ void vPortSVCHandler( void ) __attribute__ (( naked )); */ static void prvPortStartFirstTask( void ) __attribute__ (( naked )); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* @@ -191,7 +205,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = 0; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) portTASK_RETURN_ADDRESS; /* LR */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ @@ -200,6 +214,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + void vPortSVCHandler( void ) { __asm volatile ( @@ -465,8 +493,16 @@ void xPortSysTickHandler( void ) to be unsuspended then abandon the low power entry. */ if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; /* Re-enable interrupts - see comments above the cpsid instruction() above. */ diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c index e7e503f61..0579ae929 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c @@ -120,6 +120,15 @@ occurred while the SysTick counter is stopped during tickless idle calculations. */ #define portMISSED_COUNTS_FACTOR ( 45UL ) +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case is messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + /* Each task maintains its own interrupt status in the critical nesting variable. */ static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; @@ -148,6 +157,11 @@ static void prvPortStartFirstTask( void ) __attribute__ (( naked )); */ static void vPortEnableVFP( void ) __attribute__ (( naked )); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* @@ -174,7 +188,7 @@ static void prvPortStartFirstTask( void ) __attribute__ (( naked )); #endif /* configUSE_TICKLESS_IDLE */ /* - * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure + * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure * FreeRTOS API functions are not called from interrupts that have been assigned * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ @@ -202,7 +216,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = 0; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) portTASK_RETURN_ADDRESS; /* LR */ /* Save code space by skipping register initialisation. */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ @@ -219,6 +233,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + void vPortSVCHandler( void ) { __asm volatile ( @@ -406,7 +434,7 @@ void xPortPendSVHandler( void ) ( " mrs r0, psp \n" " \n" - " ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */ + " ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */ " ldr r2, [r3] \n" " \n" " tst r14, #0x10 \n" /* Is the task using the FPU context? If so, push high vfp registers. */ @@ -435,6 +463,14 @@ void xPortPendSVHandler( void ) " vldmiaeq r0!, {s16-s31} \n" " \n" " msr psp, r0 \n" + " \n" + #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata workaround. */ + #if WORKAROUND_PMU_CM001 == 1 + " push { r14 } \n" + " pop { pc } \n" + #endif + #endif + " \n" " bx r14 \n" " \n" " .align 2 \n" @@ -500,9 +536,17 @@ void xPortSysTickHandler( void ) to be unsuspended then abandon the low power entry. */ if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + /* Re-enable interrupts - see comments above the cpsid instruction() above. */ __asm volatile( "cpsie i" ); diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c index 981715943..3ed02de16 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c @@ -97,7 +97,7 @@ #define portNVIC_PENDSV_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_SYSTICK_PRI ( ( ( unsigned long ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) -/* Constants required to check the validity of an interrupt prority. */ +/* Constants required to check the validity of an interrupt priority. */ #define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) #define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) #define portAIRCR_REG ( * ( ( volatile unsigned long * ) 0xE000ED0C ) ) @@ -146,6 +146,11 @@ void xPortSysTickHandler( void ); */ extern void vPortStartFirstTask( void ); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* @@ -196,7 +201,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = 0; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) prvTaskExitError; /* LR */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ @@ -205,6 +210,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + /* * See header file for description. */ @@ -367,8 +386,16 @@ void xPortSysTickHandler( void ) to be unsuspended then abandon the low power entry. */ if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; /* Re-enable interrupts - see comments above __disable_interrupt() call above. */ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s index d6296e440..cabefbd73 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s @@ -81,11 +81,11 @@ /*-----------------------------------------------------------*/ xPortPendSVHandler: - mrs r0, psp - + mrs r0, psp + /* Get the location of the current TCB. */ - ldr r3, =pxCurrentTCB - ldr r2, [r3] + ldr r3, =pxCurrentTCB + ldr r2, [r3] /* Is the task using the FPU context? If so, push high vfp registers. */ tst r14, #0x10 @@ -93,34 +93,42 @@ xPortPendSVHandler: vstmdbeq r0!, {s16-s31} /* Save the core registers. */ - stmdb r0!, {r4-r11, r14} - + stmdb r0!, {r4-r11, r14} + /* Save the new top of stack into the first member of the TCB. */ str r0, [r2] - + stmdb sp!, {r3, r14} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 - bl vTaskSwitchContext + bl vTaskSwitchContext mov r0, #0 msr basepri, r0 ldmia sp!, {r3, r14} /* The first item in pxCurrentTCB is the task top of stack. */ - ldr r1, [r3] + ldr r1, [r3] ldr r0, [r1] - + /* Pop the core registers. */ ldmia r0!, {r4-r11, r14} - /* Is the task using the FPU context? If so, pop the high vfp registers + /* Is the task using the FPU context? If so, pop the high vfp registers too. */ tst r14, #0x10 it eq vldmiaeq r0!, {s16-s31} - - msr psp, r0 - bx r14 + + msr psp, r0 + + #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */ + #if WORKAROUND_PMU_CM001 == 1 + push { r14 } + pop { pc } + #endif + #endif + + bx r14 /*-----------------------------------------------------------*/ @@ -130,7 +138,7 @@ ulPortSetInterruptMask: mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r1 bx r14 - + /*-----------------------------------------------------------*/ vPortClearInterruptMask: @@ -148,7 +156,7 @@ vPortSVCHandler: ldmia r0!, {r4-r11, r14} msr psp, r0 mov r0, #0 - msr basepri, r0 + msr basepri, r0 bx r14 /*-----------------------------------------------------------*/ @@ -170,13 +178,13 @@ vPortEnableVFP: /* The FPU enable bits are in the CPACR. */ ldr.w r0, =0xE000ED88 ldr r1, [r0] - + /* Enable CP10 and CP11 coprocessors, then save back. */ orr r1, r1, #( 0xf << 20 ) str r1, [r0] - bx r14 - + bx r14 + END - + diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c index e37830a55..9d1e53e67 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c @@ -154,6 +154,11 @@ void vPortSVCHandler( void ); */ static void prvStartFirstTask( void ); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* @@ -204,7 +209,8 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = 0; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) prvTaskExitError; /* LR */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ @@ -213,6 +219,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + __asm void vPortSVCHandler( void ) { PRESERVE8 @@ -442,8 +462,16 @@ void xPortSysTickHandler( void ) to be unsuspended then abandon the low power entry. */ if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; /* Re-enable interrupts - see comments above __disable_irq() call above. */ diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c index eb536a209..a5b81f7bc 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c @@ -163,6 +163,12 @@ static void prvStartFirstTask( void ); * Functions defined in portasm.s to enable the VFP. */ static void prvEnableVFP( void ); + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* @@ -217,7 +223,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = 0; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) prvTaskExitError; /* LR */ /* Save code space by skipping register initialisation. */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ @@ -234,6 +240,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + __asm void vPortSVCHandler( void ) { PRESERVE8 @@ -444,6 +464,14 @@ __asm void xPortPendSVHandler( void ) vldmiaeq r0!, {s16-s31} msr psp, r0 + + #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */ + #if WORKAROUND_PMU_CM001 == 1 + push { r14 } + pop { pc } + #endif + #endif + bx r14 nop } @@ -505,8 +533,16 @@ void xPortSysTickHandler( void ) to be unsuspended then abandon the low power entry. */ if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; /* Re-enable interrupts - see comments above __disable_irq() call above. */ -- 2.39.5