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
#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. */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#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
/* Constants required to access and manipulate the SysTick. */
#define portNVIC_SYSTICK_CLK ( 0x00000004UL )
#define portNVIC_SYSTICK_INT ( 0x00000002UL )
#define portNVIC_SYSTICK_ENABLE ( 0x00000001UL )
#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. */
#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.
*/
@ -168,6 +167,13 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVI
*/
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.
*/
@ -186,6 +192,13 @@ static void prvRestoreContextOfFirstTask( void ) __attribute__(( naked )) PRIVIL
*/
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
* FreeRTOS API functions are not called from interrupts that have been assigned
@ -243,7 +256,7 @@ void vPortSVCHandler( void )
" mrs r0, psp \n"
#endif
" b %0 \n"
::"i"(prvSVCHandler):"r0"
::"i"(prvSVCHandler):"r0", "memory"
);
}
/*-----------------------------------------------------------*/
@ -266,7 +279,7 @@ uint8_t ucSVCNumber;
but do ensure the code is completely
within the specified behaviour for the
architecture. */
__asm volatile( "dsb" );
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" );
break;
@ -276,7 +289,7 @@ uint8_t ucSVCNumber;
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */
:::"r1"
::: "r1", "memory"
);
break;
@ -357,6 +370,24 @@ BaseType_t xPortStartScheduler( void )
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
register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
@ -379,7 +410,7 @@ BaseType_t xPortStartScheduler( void )
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
prvSetupTimerInterrupt();
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
@ -396,7 +427,7 @@ BaseType_t xPortStartScheduler( void )
" isb \n"
" svc %0 \n" /* System call to start first task. */
" nop \n"
:: "i" (portSVC_START_SCHEDULER) );
:: "i" (portSVC_START_SCHEDULER) : "memory" );
/* Should not get here! */
return 0;
@ -454,6 +485,8 @@ void xPortPendSVHandler( void )
" stmdb sp!, {r3, r14} \n"
" mov r0, %0 \n"
" msr basepri, r0 \n"
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
@ -499,15 +532,15 @@ uint32_t ulDummy;
* Setup the systick timer to generate the tick interrupts at the required
* 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_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
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. */
" moveq r0, #1 \n" /* CONTROL[0]==0, return true. */
" bx lr \n"
:: "i" (portSVC_RAISE_PRIVILEGE) : "r0"
:: "i" (portSVC_RAISE_PRIVILEGE) : "r0", "memory"
);
return 0;
@ -720,7 +753,7 @@ uint32_t ul;
uint8_t ucCurrentPriority;
/* 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? */
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
#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. */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#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
/* Constants required to access and manipulate the SysTick. */
#define portNVIC_SYSTICK_CLK ( 0x00000004UL )
#define portNVIC_SYSTICK_INT ( 0x00000002UL )
#define portNVIC_SYSTICK_ENABLE ( 0x00000001UL )
#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. */
#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.
*/
@ -175,6 +174,13 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVI
*/
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.
*/
@ -198,6 +204,13 @@ static void prvSVCHandler( uint32_t *pulRegisters ) __attribute__(( noinline ))
*/
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
* FreeRTOS API functions are not called from interrupts that have been assigned
@ -261,7 +274,7 @@ void vPortSVCHandler( void )
" mrs r0, psp \n"
#endif
" b %0 \n"
::"i"(prvSVCHandler):"r0"
::"i"(prvSVCHandler):"r0", "memory"
);
}
/*-----------------------------------------------------------*/
@ -284,7 +297,7 @@ uint8_t ucSVCNumber;
but do ensure the code is completely
within the specified behaviour for the
architecture. */
__asm volatile( "dsb" );
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" );
break;
@ -294,7 +307,7 @@ uint8_t ucSVCNumber;
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */
:::"r1"
::: "r1", "memory"
);
break;
@ -414,7 +427,7 @@ BaseType_t xPortStartScheduler( void )
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
prvSetupTimerInterrupt();
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
@ -425,9 +438,9 @@ BaseType_t xPortStartScheduler( void )
/* Lazy save always. */
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */
__asm volatile(
" ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */
@ -442,7 +455,7 @@ BaseType_t xPortStartScheduler( void )
" isb \n"
" svc %0 \n" /* System call to start first task. */
" nop \n"
:: "i" (portSVC_START_SCHEDULER) );
:: "i" (portSVC_START_SCHEDULER) : "memory" );
/* Should not get here! */
return 0;
@ -555,15 +568,15 @@ uint32_t ulDummy;
* Setup the systick timer to generate the tick interrupts at the required
* 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_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
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. */
" moveq r0, #1 \n" /* CONTROL[0]==0, return true. */
" bx lr \n"
:: "i" (portSVC_RAISE_PRIVILEGE) : "r0"
:: "i" (portSVC_RAISE_PRIVILEGE) : "r0", "memory"
);
return 0;
@ -791,7 +804,7 @@ uint32_t ul;
uint8_t ucCurrentPriority;
/* 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? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )