Add more "memory" clobbers into the MPU ports to make them robust to more aggressive optimisation in newer GCC version.

This commit is contained in:
Richard Barry 2017-04-10 01:58:01 +00:00
parent 0f85ead175
commit b080f13543
2 changed files with 93 additions and 47 deletions

View File

@ -86,6 +86,16 @@ task.h is included from an application file. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
/* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK ( 1UL << 2UL )
#else
/* The way the SysTick is clocked is not modified in case it is not the same
as the core. */
#define portNVIC_SYSTICK_CLK ( 0 )
#endif
/* Constants required to access and manipulate the NVIC. */ /* Constants required to access and manipulate the NVIC. */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
@ -110,7 +120,6 @@ task.h is included from an application file. */
#define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL #define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL
/* Constants required to access and manipulate the SysTick. */ /* Constants required to access and manipulate the SysTick. */
#define portNVIC_SYSTICK_CLK ( 0x00000004UL )
#define portNVIC_SYSTICK_INT ( 0x00000002UL ) #define portNVIC_SYSTICK_INT ( 0x00000002UL )
#define portNVIC_SYSTICK_ENABLE ( 0x00000001UL ) #define portNVIC_SYSTICK_ENABLE ( 0x00000001UL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
@ -139,16 +148,6 @@ task.h is included from an application file. */
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*
* Setup the timer to generate the tick interrupts.
*/
static void prvSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION;
/* /*
* Configure a number of standard MPU regions that are used by all tasks. * Configure a number of standard MPU regions that are used by all tasks.
*/ */
@ -168,6 +167,13 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVI
*/ */
BaseType_t xPortRaisePrivilege( void ) __attribute__(( naked )); BaseType_t xPortRaisePrivilege( void ) __attribute__(( naked ));
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void );
/* /*
* Standard FreeRTOS exception handlers. * Standard FreeRTOS exception handlers.
*/ */
@ -186,6 +192,13 @@ static void prvRestoreContextOfFirstTask( void ) __attribute__(( naked )) PRIVIL
*/ */
static void prvSVCHandler( uint32_t *pulRegisters ) __attribute__(( noinline )) PRIVILEGED_FUNCTION; static void prvSVCHandler( uint32_t *pulRegisters ) __attribute__(( noinline )) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* 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 * FreeRTOS API functions are not called from interrupts that have been assigned
@ -243,7 +256,7 @@ void vPortSVCHandler( void )
" mrs r0, psp \n" " mrs r0, psp \n"
#endif #endif
" b %0 \n" " b %0 \n"
::"i"(prvSVCHandler):"r0" ::"i"(prvSVCHandler):"r0", "memory"
); );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -266,7 +279,7 @@ uint8_t ucSVCNumber;
but do ensure the code is completely but do ensure the code is completely
within the specified behaviour for the within the specified behaviour for the
architecture. */ architecture. */
__asm volatile( "dsb" ); __asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" ); __asm volatile( "isb" );
break; break;
@ -276,7 +289,7 @@ uint8_t ucSVCNumber;
" mrs r1, control \n" /* Obtain current control value. */ " mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Set privilege bit. */ " bic r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */ " msr control, r1 \n" /* Write back new control value. */
:::"r1" ::: "r1", "memory"
); );
break; break;
@ -357,6 +370,24 @@ BaseType_t xPortStartScheduler( void )
ucMaxPriorityValue <<= ( uint8_t ) 0x01; ucMaxPriorityValue <<= ( uint8_t ) 0x01;
} }
#ifdef __NVIC_PRIO_BITS
{
/* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
}
#endif
#ifdef configPRIO_BITS
{
/* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
}
#endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
@ -379,7 +410,7 @@ BaseType_t xPortStartScheduler( void )
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
prvSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
@ -396,7 +427,7 @@ BaseType_t xPortStartScheduler( void )
" isb \n" " isb \n"
" svc %0 \n" /* System call to start first task. */ " svc %0 \n" /* System call to start first task. */
" nop \n" " nop \n"
:: "i" (portSVC_START_SCHEDULER) ); :: "i" (portSVC_START_SCHEDULER) : "memory" );
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -454,6 +485,8 @@ void xPortPendSVHandler( void )
" stmdb sp!, {r3, r14} \n" " stmdb sp!, {r3, r14} \n"
" mov r0, %0 \n" " mov r0, %0 \n"
" msr basepri, r0 \n" " msr basepri, r0 \n"
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n" " bl vTaskSwitchContext \n"
" mov r0, #0 \n" " mov r0, #0 \n"
" msr basepri, r0 \n" " msr basepri, r0 \n"
@ -499,15 +532,15 @@ uint32_t ulDummy;
* Setup the systick timer to generate the tick interrupts at the required * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
static void prvSetupTimerInterrupt( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{ {
/* Reset the SysTick timer. */ /* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL; portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ /* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -609,7 +642,7 @@ BaseType_t xPortRaisePrivilege( void )
" svcne %0 \n" /* Switch to privileged. */ " svcne %0 \n" /* Switch to privileged. */
" moveq r0, #1 \n" /* CONTROL[0]==0, return true. */ " moveq r0, #1 \n" /* CONTROL[0]==0, return true. */
" bx lr \n" " bx lr \n"
:: "i" (portSVC_RAISE_PRIVILEGE) : "r0" :: "i" (portSVC_RAISE_PRIVILEGE) : "r0", "memory"
); );
return 0; return 0;
@ -720,7 +753,7 @@ uint32_t ul;
uint8_t ucCurrentPriority; uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */ /* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */ /* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )

View File

@ -88,6 +88,16 @@ task.h is included from an application file. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
/* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK ( 1UL << 2UL )
#else
/* The way the SysTick is clocked is not modified in case it is not the same
as the core. */
#define portNVIC_SYSTICK_CLK ( 0 )
#endif
/* Constants required to access and manipulate the NVIC. */ /* Constants required to access and manipulate the NVIC. */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
@ -112,7 +122,6 @@ task.h is included from an application file. */
#define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL #define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL
/* Constants required to access and manipulate the SysTick. */ /* Constants required to access and manipulate the SysTick. */
#define portNVIC_SYSTICK_CLK ( 0x00000004UL )
#define portNVIC_SYSTICK_INT ( 0x00000002UL ) #define portNVIC_SYSTICK_INT ( 0x00000002UL )
#define portNVIC_SYSTICK_ENABLE ( 0x00000001UL ) #define portNVIC_SYSTICK_ENABLE ( 0x00000001UL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
@ -146,16 +155,6 @@ task.h is included from an application file. */
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*
* Setup the timer to generate the tick interrupts.
*/
static void prvSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION;
/* /*
* Configure a number of standard MPU regions that are used by all tasks. * Configure a number of standard MPU regions that are used by all tasks.
*/ */
@ -175,6 +174,13 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVI
*/ */
BaseType_t xPortRaisePrivilege( void ) __attribute__(( naked )); BaseType_t xPortRaisePrivilege( void ) __attribute__(( naked ));
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void );
/* /*
* Standard FreeRTOS exception handlers. * Standard FreeRTOS exception handlers.
*/ */
@ -198,6 +204,13 @@ static void prvSVCHandler( uint32_t *pulRegisters ) __attribute__(( noinline ))
*/ */
static void vPortEnableVFP( void ) __attribute__ (( naked )); static void vPortEnableVFP( void ) __attribute__ (( naked ));
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* 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 * FreeRTOS API functions are not called from interrupts that have been assigned
@ -261,7 +274,7 @@ void vPortSVCHandler( void )
" mrs r0, psp \n" " mrs r0, psp \n"
#endif #endif
" b %0 \n" " b %0 \n"
::"i"(prvSVCHandler):"r0" ::"i"(prvSVCHandler):"r0", "memory"
); );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -284,7 +297,7 @@ uint8_t ucSVCNumber;
but do ensure the code is completely but do ensure the code is completely
within the specified behaviour for the within the specified behaviour for the
architecture. */ architecture. */
__asm volatile( "dsb" ); __asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" ); __asm volatile( "isb" );
break; break;
@ -294,7 +307,7 @@ uint8_t ucSVCNumber;
" mrs r1, control \n" /* Obtain current control value. */ " mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Set privilege bit. */ " bic r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */ " msr control, r1 \n" /* Write back new control value. */
:::"r1" ::: "r1", "memory"
); );
break; break;
@ -414,7 +427,7 @@ BaseType_t xPortStartScheduler( void )
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
prvSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
@ -442,7 +455,7 @@ BaseType_t xPortStartScheduler( void )
" isb \n" " isb \n"
" svc %0 \n" /* System call to start first task. */ " svc %0 \n" /* System call to start first task. */
" nop \n" " nop \n"
:: "i" (portSVC_START_SCHEDULER) ); :: "i" (portSVC_START_SCHEDULER) : "memory" );
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -555,15 +568,15 @@ uint32_t ulDummy;
* Setup the systick timer to generate the tick interrupts at the required * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
static void prvSetupTimerInterrupt( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{ {
/* Clear the SysTick. */ /* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL; portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ /* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -680,7 +693,7 @@ BaseType_t xPortRaisePrivilege( void )
" svcne %0 \n" /* Switch to privileged. */ " svcne %0 \n" /* Switch to privileged. */
" moveq r0, #1 \n" /* CONTROL[0]==0, return true. */ " moveq r0, #1 \n" /* CONTROL[0]==0, return true. */
" bx lr \n" " bx lr \n"
:: "i" (portSVC_RAISE_PRIVILEGE) : "r0" :: "i" (portSVC_RAISE_PRIVILEGE) : "r0", "memory"
); );
return 0; return 0;
@ -791,7 +804,7 @@ uint32_t ul;
uint8_t ucCurrentPriority; uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */ /* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */ /* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )