Add workaround to XMC4000 silicon bug to Tasking Cortex-M4F port layer.

This commit is contained in:
Richard Barry 2013-10-14 14:03:05 +00:00
parent c1353bb12d
commit 94607d83f9
3 changed files with 119 additions and 8 deletions

View File

@ -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.
*/

View File

@ -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

View File

@ -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 );