From 0e31f09bebb729517b8b252cd54f168bb05b82e2 Mon Sep 17 00:00:00 2001 From: rtel Date: Mon, 10 Apr 2017 01:58:01 +0000 Subject: [PATCH] Add more "memory" clobbers into the MPU ports to make them robust to more aggressive optimisation in newer GCC version. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2500 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../Source/portable/GCC/ARM_CM3_MPU/port.c | 77 +++++++++++++------ .../Source/portable/GCC/ARM_CM4_MPU/port.c | 63 +++++++++------ 2 files changed, 93 insertions(+), 47 deletions(-) diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c index be041538d..e95e8c95b 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c @@ -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 ) diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4_MPU/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM4_MPU/port.c index c52078ed1..32943ff59 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4_MPU/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4_MPU/port.c @@ -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 ) -- 2.39.2