]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c
Add additional memory barriers into ARM GCC asm code to ensure no re-ordering across...
[freertos] / FreeRTOS / Source / portable / GCC / ARM_CM4F / port.c
index daf1fd42f65eaf85c842be8549f45b14a45f91f1..54cb9a754b9bc3c28ce4876bb8351b741f229cf3 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-    FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd.\r
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.\r
     All rights reserved\r
 \r
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
@@ -134,6 +134,10 @@ r0p1 port. */
 /* The systick is a 24-bit counter. */\r
 #define portMAX_24_BIT_NUMBER                          ( 0xffffffUL )\r
 \r
+/* For strict compliance with the Cortex-M spec the task start address should\r
+have bit-0 clear, as it is loaded into the PC on exit from an ISR. */\r
+#define portSTART_ADDRESS_MASK         ( ( StackType_t ) 0xfffffffeUL )\r
+\r
 /* A fiddle factor to estimate the number of SysTick counts that would have\r
 occurred while the SysTick counter is stopped during tickless idle\r
 calculations. */\r
@@ -174,7 +178,7 @@ static void prvPortStartFirstTask( void ) __attribute__ (( naked ));
 /*\r
  * Function to enable the VFP.\r
  */\r
- static void vPortEnableVFP( void ) __attribute__ (( naked ));\r
+static void vPortEnableVFP( void ) __attribute__ (( naked ));\r
 \r
 /*\r
  * Used to catch tasks that attempt to return from their implementing function.\r
@@ -233,7 +237,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
 \r
        *pxTopOfStack = portINITIAL_XPSR;       /* xPSR */\r
        pxTopOfStack--;\r
-       *pxTopOfStack = ( StackType_t ) pxCode; /* PC */\r
+       *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;    /* PC */\r
        pxTopOfStack--;\r
        *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS;        /* LR */\r
 \r
@@ -287,11 +291,17 @@ void vPortSVCHandler( void )
 \r
 static void prvPortStartFirstTask( void )\r
 {\r
+       /* Start the first task.  This also clears the bit that indicates the FPU is\r
+       in use in case the FPU was used before the scheduler was started - which\r
+       would otherwise result in the unnecessary leaving of space in the SVC stack\r
+       for lazy saving of FPU registers. */\r
        __asm volatile(\r
                                        " ldr r0, =0xE000ED08   \n" /* Use the NVIC offset register to locate the stack. */\r
                                        " ldr r0, [r0]                  \n"\r
                                        " ldr r0, [r0]                  \n"\r
                                        " msr msp, r0                   \n" /* Set the msp back to the start of the stack. */\r
+                                       " mov r0, #0                    \n" /* Clear the bit that indicates the FPU is in use, see comment above. */\r
+                                       " msr control, r0               \n"\r
                                        " cpsie i                               \n" /* Globally enable interrupts. */\r
                                        " cpsie f                               \n"\r
                                        " dsb                                   \n"\r
@@ -350,6 +360,24 @@ BaseType_t xPortStartScheduler( void )
                        ucMaxPriorityValue <<= ( uint8_t ) 0x01;\r
                }\r
 \r
+               #ifdef __NVIC_PRIO_BITS\r
+               {\r
+                       /* Check the CMSIS configuration that defines the number of\r
+                       priority bits matches the number of priority bits actually queried\r
+                       from the hardware. */\r
+                       configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );\r
+               }\r
+               #endif\r
+\r
+               #ifdef configPRIO_BITS\r
+               {\r
+                       /* Check the FreeRTOS configuration that defines the number of\r
+                       priority bits matches the number of priority bits actually queried\r
+                       from the hardware. */\r
+                       configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );\r
+               }\r
+               #endif\r
+\r
                /* Shift the priority group value back to its position within the AIRCR\r
                register. */\r
                ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;\r
@@ -445,14 +473,13 @@ void xPortPendSVHandler( void )
        "       vstmdbeq r0!, {s16-s31}                         \n"\r
        "                                                                               \n"\r
        "       stmdb r0!, {r4-r11, r14}                        \n" /* Save the core registers. */\r
-       "                                                                               \n"\r
        "       str r0, [r2]                                            \n" /* Save the new top of stack into the first member of the TCB. */\r
        "                                                                               \n"\r
        "       stmdb sp!, {r3}                                         \n"\r
        "       mov r0, %0                                                      \n"\r
        "       msr basepri, r0                                         \n"\r
        "       dsb                                                                     \n"\r
-       "   isb                                                                 \n"\r
+       "       isb                                                                     \n"\r
        "       bl vTaskSwitchContext                           \n"\r
        "       mov r0, #0                                                      \n"\r
        "       msr basepri, r0                                         \n"\r
@@ -536,7 +563,9 @@ void xPortSysTickHandler( void )
 \r
                /* Enter a critical section but don't use the taskENTER_CRITICAL()\r
                method as that will mask interrupts that should exit sleep mode. */\r
-               __asm volatile( "cpsid i" );\r
+               __asm volatile( "cpsid i" ::: "memory" );\r
+               __asm volatile( "dsb" );\r
+               __asm volatile( "isb" );\r
 \r
                /* If a context switch is pending or a task is waiting for the scheduler\r
                to be unsuspended then abandon the low power entry. */\r
@@ -555,7 +584,7 @@ void xPortSysTickHandler( void )
 \r
                        /* Re-enable interrupts - see comments above the cpsid instruction()\r
                        above. */\r
-                       __asm volatile( "cpsie i" );\r
+                       __asm volatile( "cpsie i" ::: "memory" );\r
                }\r
                else\r
                {\r
@@ -578,7 +607,7 @@ void xPortSysTickHandler( void )
                        configPRE_SLEEP_PROCESSING( xModifiableIdleTime );\r
                        if( xModifiableIdleTime > 0 )\r
                        {\r
-                               __asm volatile( "dsb" );\r
+                               __asm volatile( "dsb" ::: "memory" );\r
                                __asm volatile( "wfi" );\r
                                __asm volatile( "isb" );\r
                        }\r
@@ -593,7 +622,7 @@ void xPortSysTickHandler( void )
 \r
                        /* Re-enable interrupts - see comments above the cpsid instruction()\r
                        above. */\r
-                       __asm volatile( "cpsie i" );\r
+                       __asm volatile( "cpsie i" ::: "memory" );\r
 \r
                        if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )\r
                        {\r
@@ -673,6 +702,10 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
        }\r
        #endif /* configUSE_TICKLESS_IDLE */\r
 \r
+       /* Stop and clear the SysTick. */\r
+       portNVIC_SYSTICK_CTRL_REG = 0UL;\r
+       portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
+\r
        /* Configure SysTick to interrupt at the requested rate. */\r
        portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;\r
        portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );\r
@@ -702,7 +735,7 @@ static void vPortEnableVFP( void )
        uint8_t ucCurrentPriority;\r
 \r
                /* Obtain the number of the currently executing interrupt. */\r
-               __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );\r
+               __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );\r
 \r
                /* Is the interrupt number a user defined interrupt? */\r
                if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )\r