]> begriffs open source - freertos/blob - portable/IAR/ARM_CM4F_MPU/port.c
Paranthesize expression-like macro (#668)
[freertos] / portable / IAR / ARM_CM4F_MPU / port.c
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /*-----------------------------------------------------------
30 * Implementation of functions defined in portable.h for the ARM CM4F MPU port.
31 *----------------------------------------------------------*/
32
33 /* IAR includes. */
34 #include <intrinsics.h>
35
36 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
37  * all the API functions to use the MPU wrappers.  That should only be done when
38  * task.h is included from an application file. */
39 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
40
41 /* Scheduler includes. */
42 #include "FreeRTOS.h"
43 #include "task.h"
44
45 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
46
47 #ifndef __ARMVFP__
48     #error This port can only be used when the project options are configured to enable hardware floating point support.
49 #endif
50
51 #if ( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
52     #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http: /*www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
53 #endif
54
55 #ifndef configSYSTICK_CLOCK_HZ
56     #define configSYSTICK_CLOCK_HZ      configCPU_CLOCK_HZ
57     /* Ensure the SysTick is clocked at the same frequency as the core. */
58     #define portNVIC_SYSTICK_CLK_BIT    ( 1UL << 2UL )
59 #else
60
61 /* The way the SysTick is clocked is not modified in case it is not the same
62  * as the core. */
63     #define portNVIC_SYSTICK_CLK_BIT    ( 0 )
64 #endif
65
66 #ifndef configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS
67     #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security."
68     #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS    1
69 #endif
70
71 /* Constants required to manipulate the core.  Registers first... */
72 #define portNVIC_SYSTICK_CTRL_REG                 ( *( ( volatile uint32_t * ) 0xe000e010 ) )
73 #define portNVIC_SYSTICK_LOAD_REG                 ( *( ( volatile uint32_t * ) 0xe000e014 ) )
74 #define portNVIC_SYSTICK_CURRENT_VALUE_REG        ( *( ( volatile uint32_t * ) 0xe000e018 ) )
75 #define portNVIC_SHPR3_REG                        ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
76 #define portNVIC_SHPR2_REG                        ( *( ( volatile uint32_t * ) 0xe000ed1c ) )
77 #define portNVIC_SYS_CTRL_STATE_REG               ( *( ( volatile uint32_t * ) 0xe000ed24 ) )
78 #define portNVIC_MEM_FAULT_ENABLE                 ( 1UL << 16UL )
79
80 /* Constants required to access and manipulate the MPU. */
81 #define portMPU_TYPE_REG                          ( *( ( volatile uint32_t * ) 0xe000ed90 ) )
82 #define portMPU_REGION_BASE_ADDRESS_REG           ( *( ( volatile uint32_t * ) 0xe000ed9C ) )
83 #define portMPU_REGION_ATTRIBUTE_REG              ( *( ( volatile uint32_t * ) 0xe000edA0 ) )
84 #define portMPU_CTRL_REG                          ( *( ( volatile uint32_t * ) 0xe000ed94 ) )
85 #define portEXPECTED_MPU_TYPE_VALUE               ( configTOTAL_MPU_REGIONS << 8UL )
86 #define portMPU_ENABLE                            ( 0x01UL )
87 #define portMPU_BACKGROUND_ENABLE                 ( 1UL << 2UL )
88 #define portPRIVILEGED_EXECUTION_START_ADDRESS    ( 0UL )
89 #define portMPU_REGION_VALID                      ( 0x10UL )
90 #define portMPU_REGION_ENABLE                     ( 0x01UL )
91 #define portPERIPHERALS_START_ADDRESS             0x40000000UL
92 #define portPERIPHERALS_END_ADDRESS               0x5FFFFFFFUL
93
94 /* ...then bits in the registers. */
95 #define portNVIC_SYSTICK_INT_BIT                  ( 1UL << 1UL )
96 #define portNVIC_SYSTICK_ENABLE_BIT               ( 1UL << 0UL )
97 #define portNVIC_SYSTICK_COUNT_FLAG_BIT           ( 1UL << 16UL )
98 #define portNVIC_PENDSVCLEAR_BIT                  ( 1UL << 27UL )
99 #define portNVIC_PEND_SYSTICK_CLEAR_BIT           ( 1UL << 25UL )
100
101 /* Constants used to detect Cortex-M7 r0p0 and r0p1 cores, and ensure
102  * that a work around is active for errata 837070. */
103 #define portCPUID                                 ( *( ( volatile uint32_t * ) 0xE000ed00 ) )
104 #define portCORTEX_M7_r0p1_ID                     ( 0x410FC271UL )
105 #define portCORTEX_M7_r0p0_ID                     ( 0x410FC270UL )
106
107 #define portMIN_INTERRUPT_PRIORITY                ( 255UL )
108 #define portNVIC_PENDSV_PRI                       ( ( ( uint32_t ) portMIN_INTERRUPT_PRIORITY ) << 16UL )
109 #define portNVIC_SYSTICK_PRI                      ( ( ( uint32_t ) portMIN_INTERRUPT_PRIORITY ) << 24UL )
110 #define portNVIC_SVC_PRI                          ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL )
111
112 /* Constants required to check the validity of an interrupt priority. */
113 #define portFIRST_USER_INTERRUPT_NUMBER           ( 16 )
114 #define portNVIC_IP_REGISTERS_OFFSET_16           ( 0xE000E3F0 )
115 #define portAIRCR_REG                             ( *( ( volatile uint32_t * ) 0xE000ED0C ) )
116 #define portMAX_8_BIT_VALUE                       ( ( uint8_t ) 0xff )
117 #define portTOP_BIT_OF_BYTE                       ( ( uint8_t ) 0x80 )
118 #define portMAX_PRIGROUP_BITS                     ( ( uint8_t ) 7 )
119 #define portPRIORITY_GROUP_MASK                   ( 0x07UL << 8UL )
120 #define portPRIGROUP_SHIFT                        ( 8UL )
121
122 /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
123 #define portVECTACTIVE_MASK                       ( 0xFFUL )
124
125 /* Constants required to manipulate the VFP. */
126 #define portFPCCR                                 ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
127 #define portASPEN_AND_LSPEN_BITS                  ( 0x3UL << 30UL )
128
129 /* Constants required to set up the initial stack. */
130 #define portINITIAL_XPSR                          ( 0x01000000 )
131 #define portINITIAL_EXC_RETURN                    ( 0xfffffffd )
132 #define portINITIAL_CONTROL_IF_UNPRIVILEGED       ( 0x03 )
133 #define portINITIAL_CONTROL_IF_PRIVILEGED         ( 0x02 )
134
135 /* Offsets in the stack to the parameters when inside the SVC handler. */
136 #define portOFFSET_TO_PC                          ( 6 )
137
138 /* The systick is a 24-bit counter. */
139 #define portMAX_24_BIT_NUMBER                     ( 0xffffffUL )
140
141 /* A fiddle factor to estimate the number of SysTick counts that would have
142  * occurred while the SysTick counter is stopped during tickless idle
143  * calculations. */
144 #define portMISSED_COUNTS_FACTOR                  ( 45UL )
145
146 /* For strict compliance with the Cortex-M spec the task start address should
147  * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
148 #define portSTART_ADDRESS_MASK                    ( ( StackType_t ) 0xfffffffeUL )
149
150 /*
151  * Configure a number of standard MPU regions that are used by all tasks.
152  */
153 static void prvSetupMPU( void ) PRIVILEGED_FUNCTION;
154
155 /*
156  * Return the smallest MPU region size that a given number of bytes will fit
157  * into.  The region size is returned as the value that should be programmed
158  * into the region attribute register for that region.
159  */
160 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION;
161
162 /*
163  * Setup the timer to generate the tick interrupts.  The implementation in this
164  * file is weak to allow application writers to change the timer used to
165  * generate the tick interrupt.
166  */
167 void vPortSetupTimerInterrupt( void );
168
169 /*
170  * Exception handlers.
171  */
172 void xPortSysTickHandler( void ) PRIVILEGED_FUNCTION;
173
174 /*
175  * Start first task is a separate function so it can be tested in isolation.
176  */
177 extern void vPortStartFirstTask( void ) PRIVILEGED_FUNCTION;
178
179 /*
180  * Turn the VFP on.
181  */
182 extern void vPortEnableVFP( void );
183
184 /*
185  * The C portion of the SVC handler.
186  */
187 void vPortSVCHandler_C( uint32_t * pulParam );
188
189 /*
190  * Called from the SVC handler used to start the scheduler.
191  */
192 extern void vPortRestoreContextOfFirstTask( void ) PRIVILEGED_FUNCTION;
193
194 /**
195  * @brief Enter critical section.
196  */
197 #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
198     void vPortEnterCritical( void ) FREERTOS_SYSTEM_CALL;
199 #else
200     void vPortEnterCritical( void ) PRIVILEGED_FUNCTION;
201 #endif
202
203 /**
204  * @brief Exit from critical section.
205  */
206 #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
207     void vPortExitCritical( void ) FREERTOS_SYSTEM_CALL;
208 #else
209     void vPortExitCritical( void ) PRIVILEGED_FUNCTION;
210 #endif
211 /*-----------------------------------------------------------*/
212
213 /* Each task maintains its own interrupt status in the critical nesting
214  * variable. */
215 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
216
217 /*
218  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
219  * FreeRTOS API functions are not called from interrupts that have been assigned
220  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
221  */
222 #if ( configASSERT_DEFINED == 1 )
223     static uint8_t ucMaxSysCallPriority = 0;
224     static uint32_t ulMaxPRIGROUPValue = 0;
225     static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
226 #endif /* configASSERT_DEFINED */
227
228 /*-----------------------------------------------------------*/
229
230 /*
231  * See header file for description.
232  */
233 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
234                                      TaskFunction_t pxCode,
235                                      void * pvParameters,
236                                      BaseType_t xRunPrivileged )
237 {
238     /* Simulate the stack frame as it would be created by a context switch
239      * interrupt. */
240
241     /* Offset added to account for the way the MCU uses the stack on entry/exit
242      * of interrupts, and to ensure alignment. */
243     pxTopOfStack--;
244
245     *pxTopOfStack = portINITIAL_XPSR;                                    /* xPSR */
246     pxTopOfStack--;
247     *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
248     pxTopOfStack--;
249     *pxTopOfStack = ( StackType_t ) 0;                                   /* LR */
250
251     /* Save code space by skipping register initialisation. */
252     pxTopOfStack -= 5;                            /* R12, R3, R2 and R1. */
253     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
254
255     /* A save method is being used that requires each task to maintain its
256      * own exec return value. */
257     pxTopOfStack--;
258     *pxTopOfStack = portINITIAL_EXC_RETURN;
259
260     pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
261
262     if( xRunPrivileged == pdTRUE )
263     {
264         *pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;
265     }
266     else
267     {
268         *pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;
269     }
270
271     return pxTopOfStack;
272 }
273 /*-----------------------------------------------------------*/
274
275 void vPortSVCHandler_C( uint32_t * pulParam )
276 {
277     uint8_t ucSVCNumber;
278     uint32_t ulPC;
279
280     #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
281         extern uint32_t __syscalls_flash_start__[];
282         extern uint32_t __syscalls_flash_end__[];
283     #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
284
285     /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
286      * argument (r0) is pulParam[ 0 ]. */
287     ulPC = pulParam[ portOFFSET_TO_PC ];
288     ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
289
290     switch( ucSVCNumber )
291     {
292         case portSVC_START_SCHEDULER:
293             portNVIC_SHPR2_REG |= portNVIC_SVC_PRI;
294             vPortRestoreContextOfFirstTask();
295             break;
296
297         case portSVC_YIELD:
298             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
299
300             /* Barriers are normally not required
301              * but do ensure the code is completely
302              * within the specified behaviour for the
303              * architecture. */
304             __asm volatile ( "dsb" ::: "memory" );
305             __asm volatile ( "isb" );
306
307             break;
308
309             #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
310                 case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the
311                                                * svc was raised from any of the
312                                                * system calls. */
313
314                     if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
315                         ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
316                     {
317                         __asm volatile
318                         (
319                             "   mrs r1, control     \n" /* Obtain current control value. */
320                             "   bic r1, r1, #1      \n" /* Set privilege bit. */
321                             "   msr control, r1     \n" /* Write back new control value. */
322                             ::: "r1", "memory"
323                         );
324                     }
325
326                     break;
327             #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
328                 case portSVC_RAISE_PRIVILEGE:
329                     __asm volatile
330                     (
331                         "   mrs r1, control     \n" /* Obtain current control value. */
332                         "   bic r1, r1, #1      \n" /* Set privilege bit. */
333                         "   msr control, r1     \n" /* Write back new control value. */
334                         ::: "r1", "memory"
335                     );
336                     break;
337                     #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
338
339                 default: /* Unknown SVC call. */
340                     break;
341     }
342 }
343 /*-----------------------------------------------------------*/
344
345 /*
346  * See header file for description.
347  */
348 BaseType_t xPortStartScheduler( void )
349 {
350     /* Errata 837070 workaround must only be enabled on Cortex-M7 r0p0
351      * and r0p1 cores. */
352     #if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )
353         configASSERT( ( portCPUID == portCORTEX_M7_r0p1_ID ) || ( portCPUID == portCORTEX_M7_r0p0_ID ) );
354     #else
355
356         /* When using this port on a Cortex-M7 r0p0 or r0p1 core, define
357          * configENABLE_ERRATA_837070_WORKAROUND to 1 in your
358          * FreeRTOSConfig.h. */
359         configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
360         configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
361     #endif
362
363     #if ( configASSERT_DEFINED == 1 )
364     {
365         volatile uint8_t ucOriginalPriority;
366         volatile uint32_t ulImplementedPrioBits = 0;
367         volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
368         volatile uint8_t ucMaxPriorityValue;
369
370         /* Determine the maximum priority from which ISR safe FreeRTOS API
371          * functions can be called.  ISR safe functions are those that end in
372          * "FromISR".  FreeRTOS maintains separate thread and ISR API functions to
373          * ensure interrupt entry is as fast and simple as possible.
374          *
375          * Save the interrupt priority value that is about to be clobbered. */
376         ucOriginalPriority = *pucFirstUserPriorityRegister;
377
378         /* Determine the number of priority bits available.  First write to all
379          * possible bits. */
380         *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
381
382         /* Read the value back to see how many bits stuck. */
383         ucMaxPriorityValue = *pucFirstUserPriorityRegister;
384
385         /* Use the same mask on the maximum system call priority. */
386         ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
387
388         /* Check that the maximum system call priority is nonzero after
389          * accounting for the number of priority bits supported by the
390          * hardware. A priority of 0 is invalid because setting the BASEPRI
391          * register to 0 unmasks all interrupts, and interrupts with priority 0
392          * cannot be masked using BASEPRI.
393          * See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
394         configASSERT( ucMaxSysCallPriority );
395
396         /* Calculate the maximum acceptable priority group value for the number
397          * of bits read back. */
398
399         while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
400         {
401             ulImplementedPrioBits++;
402             ucMaxPriorityValue <<= ( uint8_t ) 0x01;
403         }
404
405         if( ulImplementedPrioBits == 8 )
406         {
407             /* When the hardware implements 8 priority bits, there is no way for
408             * the software to configure PRIGROUP to not have sub-priorities. As
409             * a result, the least significant bit is always used for sub-priority
410             * and there are 128 preemption priorities and 2 sub-priorities.
411             *
412             * This may cause some confusion in some cases - for example, if
413             * configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
414             * priority interrupts will be masked in Critical Sections as those
415             * are at the same preemption priority. This may appear confusing as
416             * 4 is higher (numerically lower) priority than
417             * configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
418             * have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
419             * to 4, this confusion does not happen and the behaviour remains the same.
420             *
421             * The following assert ensures that the sub-priority bit in the
422             * configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
423             * confusion. */
424             configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
425             ulMaxPRIGROUPValue = 0;
426         }
427         else
428         {
429             ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
430         }
431
432         #ifdef __NVIC_PRIO_BITS
433         {
434             /*
435              * Check that the number of implemented priority bits queried from
436              * hardware is at least as many as specified in the CMSIS
437              * __NVIC_PRIO_BITS configuration macro.
438              */
439             configASSERT( ulImplementedPrioBits >= __NVIC_PRIO_BITS );
440         }
441         #endif
442
443         #ifdef configPRIO_BITS
444         {
445             /*
446              * Check that the number of implemented priority bits queried from
447              * hardware is at least as many as specified in the FreeRTOS
448              * configPRIO_BITS configuration macro.
449              */
450             configASSERT( ulImplementedPrioBits >= configPRIO_BITS );
451         }
452         #endif
453
454         /* Shift the priority group value back to its position within the AIRCR
455          * register. */
456         ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
457         ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
458
459         /* Restore the clobbered interrupt priority register to its original
460          * value. */
461         *pucFirstUserPriorityRegister = ucOriginalPriority;
462     }
463     #endif /* configASSERT_DEFINED */
464
465     /* Make PendSV and SysTick the lowest priority interrupts. */
466     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
467     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
468
469     /* Configure the regions in the MPU that are common to all tasks. */
470     prvSetupMPU();
471
472     /* Start the timer that generates the tick ISR.  Interrupts are disabled
473      * here already. */
474     vPortSetupTimerInterrupt();
475
476     /* Initialise the critical nesting count ready for the first task. */
477     uxCriticalNesting = 0;
478
479     /* Ensure the VFP is enabled - it should be anyway. */
480     vPortEnableVFP();
481
482     /* Lazy save always. */
483     *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
484
485     /* Start the first task. */
486     vPortStartFirstTask();
487
488     /* Should not get here! */
489     return 0;
490 }
491 /*-----------------------------------------------------------*/
492
493 void vPortEndScheduler( void )
494 {
495     /* Not implemented in ports where there is nothing to return to.
496      * Artificially force an assert. */
497     configASSERT( uxCriticalNesting == 1000UL );
498 }
499 /*-----------------------------------------------------------*/
500
501 void vPortEnterCritical( void )
502 {
503     #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
504         if( portIS_PRIVILEGED() == pdFALSE )
505         {
506             portRAISE_PRIVILEGE();
507             portMEMORY_BARRIER();
508
509             portDISABLE_INTERRUPTS();
510             uxCriticalNesting++;
511
512             /* This is not the interrupt safe version of the enter critical function so
513              * assert() if it is being called from an interrupt context.  Only API
514              * functions that end in "FromISR" can be used in an interrupt.  Only assert if
515              * the critical nesting count is 1 to protect against recursive calls if the
516              * assert function also uses a critical section. */
517             if( uxCriticalNesting == 1 )
518             {
519                 configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
520             }
521
522             portMEMORY_BARRIER();
523
524             portRESET_PRIVILEGE();
525             portMEMORY_BARRIER();
526         }
527         else
528         {
529             portDISABLE_INTERRUPTS();
530             uxCriticalNesting++;
531
532             /* This is not the interrupt safe version of the enter critical function so
533              * assert() if it is being called from an interrupt context.  Only API
534              * functions that end in "FromISR" can be used in an interrupt.  Only assert if
535              * the critical nesting count is 1 to protect against recursive calls if the
536              * assert function also uses a critical section. */
537             if( uxCriticalNesting == 1 )
538             {
539                 configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
540             }
541         }
542     #else /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
543         portDISABLE_INTERRUPTS();
544         uxCriticalNesting++;
545
546         /* This is not the interrupt safe version of the enter critical function so
547          * assert() if it is being called from an interrupt context.  Only API
548          * functions that end in "FromISR" can be used in an interrupt.  Only assert if
549          * the critical nesting count is 1 to protect against recursive calls if the
550          * assert function also uses a critical section. */
551         if( uxCriticalNesting == 1 )
552         {
553             configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
554         }
555     #endif /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
556 }
557 /*-----------------------------------------------------------*/
558
559 void vPortExitCritical( void )
560 {
561     #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
562         if( portIS_PRIVILEGED() == pdFALSE )
563         {
564             portRAISE_PRIVILEGE();
565             portMEMORY_BARRIER();
566
567             configASSERT( uxCriticalNesting );
568             uxCriticalNesting--;
569
570             if( uxCriticalNesting == 0 )
571             {
572                 portENABLE_INTERRUPTS();
573             }
574
575             portMEMORY_BARRIER();
576
577             portRESET_PRIVILEGE();
578             portMEMORY_BARRIER();
579         }
580         else
581         {
582             configASSERT( uxCriticalNesting );
583             uxCriticalNesting--;
584
585             if( uxCriticalNesting == 0 )
586             {
587                 portENABLE_INTERRUPTS();
588             }
589         }
590     #else /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
591         configASSERT( uxCriticalNesting );
592         uxCriticalNesting--;
593
594         if( uxCriticalNesting == 0 )
595         {
596             portENABLE_INTERRUPTS();
597         }
598     #endif /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
599 }
600 /*-----------------------------------------------------------*/
601
602 void xPortSysTickHandler( void )
603 {
604     /* The SysTick runs at the lowest interrupt priority, so when this interrupt
605      * executes all interrupts must be unmasked.  There is therefore no need to
606      * save and then restore the interrupt mask value as its value is already
607      * known. */
608     portDISABLE_INTERRUPTS();
609     {
610         /* Increment the RTOS tick. */
611         if( xTaskIncrementTick() != pdFALSE )
612         {
613             /* A context switch is required.  Context switching is performed in
614              * the PendSV interrupt.  Pend the PendSV interrupt. */
615             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
616         }
617     }
618     portENABLE_INTERRUPTS();
619 }
620 /*-----------------------------------------------------------*/
621
622 /*
623  * Setup the systick timer to generate the tick interrupts at the required
624  * frequency.
625  */
626 __weak void vPortSetupTimerInterrupt( void )
627 {
628     /* Stop and clear the SysTick. */
629     portNVIC_SYSTICK_CTRL_REG = 0UL;
630     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
631
632     /* Configure SysTick to interrupt at the requested rate. */
633     portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
634     portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
635 }
636 /*-----------------------------------------------------------*/
637
638 static void prvSetupMPU( void )
639 {
640     extern uint32_t __privileged_functions_start__[];
641     extern uint32_t __privileged_functions_end__[];
642     extern uint32_t __FLASH_segment_start__[];
643     extern uint32_t __FLASH_segment_end__[];
644     extern uint32_t __privileged_data_start__[];
645     extern uint32_t __privileged_data_end__[];
646
647     /* The only permitted number of regions are 8 or 16. */
648     configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) );
649
650     /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */
651     configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );
652
653     /* Check the expected MPU is present. */
654     if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
655     {
656         /* First setup the unprivileged flash for unprivileged read only access. */
657         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
658                                           ( portMPU_REGION_VALID ) |
659                                           ( portUNPRIVILEGED_FLASH_REGION );
660
661         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |
662                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
663                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |
664                                        ( portMPU_REGION_ENABLE );
665
666         /* Setup the privileged flash for privileged only access.  This is where
667          * the kernel code is placed. */
668         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */
669                                           ( portMPU_REGION_VALID ) |
670                                           ( portPRIVILEGED_FLASH_REGION );
671
672         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |
673                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
674                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) |
675                                        ( portMPU_REGION_ENABLE );
676
677         /* Setup the privileged data RAM region.  This is where the kernel data
678          * is placed. */
679         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
680                                           ( portMPU_REGION_VALID ) |
681                                           ( portPRIVILEGED_RAM_REGION );
682
683         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
684                                        ( portMPU_REGION_EXECUTE_NEVER ) |
685                                        ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
686                                        prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
687                                        ( portMPU_REGION_ENABLE );
688
689         /* By default allow everything to access the general peripherals.  The
690          * system peripherals and registers are protected. */
691         portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
692                                           ( portMPU_REGION_VALID ) |
693                                           ( portGENERAL_PERIPHERALS_REGION );
694
695         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) |
696                                        ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) |
697                                        ( portMPU_REGION_ENABLE );
698
699         /* Enable the memory fault exception. */
700         portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;
701
702         /* Enable the MPU with the background region configured. */
703         portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );
704     }
705 }
706 /*-----------------------------------------------------------*/
707
708 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
709 {
710     uint32_t ulRegionSize, ulReturnValue = 4;
711
712     /* 32 is the smallest region size, 31 is the largest valid value for
713      * ulReturnValue. */
714     for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
715     {
716         if( ulActualSizeInBytes <= ulRegionSize )
717         {
718             break;
719         }
720         else
721         {
722             ulReturnValue++;
723         }
724     }
725
726     /* Shift the code by one before returning so it can be written directly
727      * into the the correct bit position of the attribute register. */
728     return( ulReturnValue << 1UL );
729 }
730 /*-----------------------------------------------------------*/
731
732 void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
733                                 const struct xMEMORY_REGION * const xRegions,
734                                 StackType_t * pxBottomOfStack,
735                                 uint32_t ulStackDepth )
736 {
737     extern uint32_t __SRAM_segment_start__[];
738     extern uint32_t __SRAM_segment_end__[];
739     extern uint32_t __privileged_data_start__[];
740     extern uint32_t __privileged_data_end__[];
741     int32_t lIndex;
742     uint32_t ul;
743
744     if( xRegions == NULL )
745     {
746         /* No MPU regions are specified so allow access to all RAM. */
747         xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
748             ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */
749             ( portMPU_REGION_VALID ) |
750             ( portSTACK_REGION );                     /* Region number. */
751
752         xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
753             ( portMPU_REGION_READ_WRITE ) |
754             ( portMPU_REGION_EXECUTE_NEVER ) |
755             ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
756             ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
757             ( portMPU_REGION_ENABLE );
758
759         /* Invalidate user configurable regions. */
760         for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
761         {
762             xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
763             xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
764         }
765     }
766     else
767     {
768         /* This function is called automatically when the task is created - in
769          * which case the stack region parameters will be valid.  At all other
770          * times the stack parameters will not be valid and it is assumed that the
771          * stack region has already been configured. */
772         if( ulStackDepth > 0 )
773         {
774             /* Define the region that allows access to the stack. */
775             xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
776                 ( ( uint32_t ) pxBottomOfStack ) |
777                 ( portMPU_REGION_VALID ) |
778                 ( portSTACK_REGION ); /* Region number. */
779
780             xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
781                 ( portMPU_REGION_READ_WRITE ) |
782                 ( portMPU_REGION_EXECUTE_NEVER ) |
783                 ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |
784                 ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
785                 ( portMPU_REGION_ENABLE );
786         }
787
788         lIndex = 0;
789
790         for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
791         {
792             if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
793             {
794                 /* Translate the generic region definition contained in
795                  * xRegions into the CM4 specific MPU settings that are then
796                  * stored in xMPUSettings. */
797                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
798                     ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
799                     ( portMPU_REGION_VALID ) |
800                     ( ul - 1UL ); /* Region number. */
801
802                 xMPUSettings->xRegion[ ul ].ulRegionAttribute =
803                     ( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |
804                     ( xRegions[ lIndex ].ulParameters ) |
805                     ( portMPU_REGION_ENABLE );
806             }
807             else
808             {
809                 /* Invalidate the region. */
810                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
811                 xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
812             }
813
814             lIndex++;
815         }
816     }
817 }
818 /*-----------------------------------------------------------*/
819
820 #if ( configASSERT_DEFINED == 1 )
821
822     void vPortValidateInterruptPriority( void )
823     {
824         uint32_t ulCurrentInterrupt;
825         uint8_t ucCurrentPriority;
826
827         /* Obtain the number of the currently executing interrupt. */
828         __asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );
829
830         /* Is the interrupt number a user defined interrupt? */
831         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
832         {
833             /* Look up the interrupt's priority. */
834             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
835
836             /* The following assertion will fail if a service routine (ISR) for
837              * an interrupt that has been assigned a priority above
838              * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
839              * function.  ISR safe FreeRTOS API functions must *only* be called
840              * from interrupts that have been assigned a priority at or below
841              * configMAX_SYSCALL_INTERRUPT_PRIORITY.
842              *
843              * Numerically low interrupt priority numbers represent logically high
844              * interrupt priorities, therefore the priority of the interrupt must
845              * be set to a value equal to or numerically *higher* than
846              * configMAX_SYSCALL_INTERRUPT_PRIORITY.
847              *
848              * Interrupts that  use the FreeRTOS API must not be left at their
849              * default priority of  zero as that is the highest possible priority,
850              * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
851              * and  therefore also guaranteed to be invalid.
852              *
853              * FreeRTOS maintains separate thread and ISR API functions to ensure
854              * interrupt entry is as fast and simple as possible.
855              *
856              * The following links provide detailed information:
857              * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
858              * https://www.FreeRTOS.org/FAQHelp.html */
859             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
860         }
861
862         /* Priority grouping:  The interrupt controller (NVIC) allows the bits
863          * that define each interrupt's priority to be split between bits that
864          * define the interrupt's pre-emption priority bits and bits that define
865          * the interrupt's sub-priority.  For simplicity all bits must be defined
866          * to be pre-emption priority bits.  The following assertion will fail if
867          * this is not the case (if some bits represent a sub-priority).
868          *
869          * If the application only uses CMSIS libraries for interrupt
870          * configuration then the correct setting can be achieved on all Cortex-M
871          * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
872          * scheduler.  Note however that some vendor specific peripheral libraries
873          * assume a non-zero priority group setting, in which cases using a value
874          * of zero will result in unpredictable behaviour. */
875         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
876     }
877
878 #endif /* configASSERT_DEFINED */
879 /*-----------------------------------------------------------*/