From: richardbarry Date: Mon, 14 Oct 2013 14:03:05 +0000 (+0000) Subject: Add workaround to XMC4000 silicon bug to Tasking Cortex-M4F port layer. X-Git-Tag: V7.5.3~3 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=3c3571ea5353e2dff8ca6484b1c872bb97caea54;p=freertos Add workaround to XMC4000 silicon bug to Tasking Cortex-M4F port layer. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2063 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c index d167e4a15..c070c5c5c 100644 --- a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c @@ -88,6 +88,15 @@ #define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_EXEC_RETURN ( 0xfffffffd ) +/* 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 + /* The priority used by the kernel is assigned to a variable to make access from inline assembler easier. */ const unsigned long ulKernelPriority = configKERNEL_INTERRUPT_PRIORITY; @@ -112,6 +121,11 @@ void SysTick_Handler( void ); extern void vPortEnableVFP( void ); extern void vPortStartFirstTask( void ); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /* This exists purely to allow the const to be used from within the port_asm.asm assembly file. */ const unsigned long ulMaxSyscallInterruptPriorityConst = configMAX_SYSCALL_INTERRUPT_PRIORITY; @@ -134,7 +148,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. */ @@ -151,6 +165,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( ulCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + /* * See header file for description. */ diff --git a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port_asm.asm b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port_asm.asm index 413de2e1c..93ff21285 100644 --- a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port_asm.asm +++ b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port_asm.asm @@ -51,21 +51,26 @@ ; licensing and training services. ;*/ + .extern pxCurrentTCB .extern vTaskSwitchContext .extern ulMaxSyscallInterruptPriorityConst - .global PendSV_Handler + .global _vector_14 + .global _lc_ref__vector_pp_14 .global SVC_Handler .global vPortStartFirstTask .global vPortEnableVFP + .global ulPortSetInterruptMask + .global vPortClearInterruptMask ;----------------------------------------------------------- .section .text .thumb .align 4 -PendSV_Handler: .type func +_vector_14: .type func + mrs r0, psp ;Get the location of the current TCB. @@ -106,7 +111,60 @@ PendSV_Handler: .type func msr psp, r0 bx r14 - .size PendSV_Handler, $-PendSV_Handler + .size _vector_14, $-_vector_14 + .endsec + +;----------------------------------------------------------- + +; This function is an XMC4000 silicon errata workaround. It will get used when +; the SILICON_BUG_PMC_CM_001 linker macro is defined. + .section .text + .thumb + .align 4 +_lc_ref__vector_pp_14: .type func + + mrs r0, psp + + ;Get the location of the current TCB. + ldr.w r3, =pxCurrentTCB + ldr r2, [r3] + + ;Is the task using the FPU context? If so, push high vfp registers. + tst r14, #0x10 + it eq + vstmdbeq r0!, {s16-s31} + + ;Save the core registers. + 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} + ldr.w r0, =ulMaxSyscallInterruptPriorityConst + msr basepri, r0 + 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 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 too. + tst r14, #0x10 + it eq + vldmiaeq r0!, {s16-s31} + + msr psp, r0 + push { lr } + pop { pc } ; XMC4000 specific errata workaround. Do not used "bx lr" here. + + .size _lc_ref__vector_pp_14, $-_lc_ref__vector_pp_14 .endsec ;----------------------------------------------------------- @@ -163,6 +221,31 @@ vPortEnableVFP .type func .size vPortEnableVFP, $-vPortEnableVFP .endsec +;----------------------------------------------------------- + + .section .text + .thumb + .align 4 +ulPortSetInterruptMask: + mrs r0, basepri + ldr.w r1, =ulMaxSyscallInterruptPriorityConst + msr basepri, r1 + bx r14 + .size ulPortSetInterruptMask, $-ulPortSetInterruptMask + .endsec + +;----------------------------------------------------------- + + .section .text + .thumb + .align 4 +vPortClearInterruptMask: + msr basepri, r0 + bx r14 + .size vPortClearInterruptMask, $-vPortClearInterruptMask + .endsec + +;----------------------------------------------------------- .end diff --git a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/portmacro.h index 45ac21cb0..a49f5eb6b 100644 --- a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/portmacro.h @@ -131,10 +131,10 @@ extern void vPortYield( void ); */ #define portCLEAR_INTERRUPT_MASK() __set_BASEPRI( 0 ) -/* FAQ: Setting BASEPRI to 0 is not a bug. Please see -http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html before disagreeing. */ -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x +extern unsigned long ulPortSetInterruptMask( void ); +extern void vPortClearInterruptMask( unsigned long ulNewMask ); +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask( x ) extern void vPortEnterCritical( void );