1 /*
2  * FreeRTOS Kernel V11.1.0
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 #include "mpu_syscall_numbers.h"
45 
46 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
47 
48 #ifndef __ARMVFP__
49     #error This port can only be used when the project options are configured to enable hardware floating point support.
50 #endif
51 
52 #if ( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
53     #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http: /*www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
54 #endif
55 
56 #ifndef configSYSTICK_CLOCK_HZ
57     #define configSYSTICK_CLOCK_HZ      configCPU_CLOCK_HZ
58     /* Ensure the SysTick is clocked at the same frequency as the core. */
59     #define portNVIC_SYSTICK_CLK_BIT    ( 1UL << 2UL )
60 #else
61 
62 /* The way the SysTick is clocked is not modified in case it is not the same
63  * as the core. */
64     #define portNVIC_SYSTICK_CLK_BIT    ( 0 )
65 #endif
66 
67 #ifndef configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS
68     #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security."
69     #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS    1
70 #endif
71 
72 /* Prototype of all Interrupt Service Routines (ISRs). */
73 typedef void ( * portISR_t )( void );
74 
75 /* Constants required to manipulate the core.  Registers first... */
76 #define portNVIC_SYSTICK_CTRL_REG                 ( *( ( volatile uint32_t * ) 0xe000e010 ) )
77 #define portNVIC_SYSTICK_LOAD_REG                 ( *( ( volatile uint32_t * ) 0xe000e014 ) )
78 #define portNVIC_SYSTICK_CURRENT_VALUE_REG        ( *( ( volatile uint32_t * ) 0xe000e018 ) )
79 #define portNVIC_SHPR3_REG                        ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
80 #define portNVIC_SHPR2_REG                        ( *( ( volatile uint32_t * ) 0xe000ed1c ) )
81 #define portNVIC_SYS_CTRL_STATE_REG               ( *( ( volatile uint32_t * ) 0xe000ed24 ) )
82 #define portNVIC_MEM_FAULT_ENABLE                 ( 1UL << 16UL )
83 
84 /* Constants required to access and manipulate the MPU. */
85 #define portMPU_TYPE_REG                          ( *( ( volatile uint32_t * ) 0xe000ed90 ) )
86 #define portMPU_REGION_BASE_ADDRESS_REG           ( *( ( volatile uint32_t * ) 0xe000ed9C ) )
87 #define portMPU_REGION_ATTRIBUTE_REG              ( *( ( volatile uint32_t * ) 0xe000edA0 ) )
88 #define portMPU_CTRL_REG                          ( *( ( volatile uint32_t * ) 0xe000ed94 ) )
89 #define portEXPECTED_MPU_TYPE_VALUE               ( configTOTAL_MPU_REGIONS << 8UL )
90 #define portMPU_ENABLE                            ( 0x01UL )
91 #define portMPU_BACKGROUND_ENABLE                 ( 1UL << 2UL )
92 #define portPRIVILEGED_EXECUTION_START_ADDRESS    ( 0UL )
93 #define portMPU_REGION_VALID                      ( 0x10UL )
94 #define portMPU_REGION_ENABLE                     ( 0x01UL )
95 #define portPERIPHERALS_START_ADDRESS             0x40000000UL
96 #define portPERIPHERALS_END_ADDRESS               0x5FFFFFFFUL
97 
98 /* ...then bits in the registers. */
99 #define portNVIC_SYSTICK_INT_BIT                  ( 1UL << 1UL )
100 #define portNVIC_SYSTICK_ENABLE_BIT               ( 1UL << 0UL )
101 #define portNVIC_SYSTICK_COUNT_FLAG_BIT           ( 1UL << 16UL )
102 #define portNVIC_PENDSVCLEAR_BIT                  ( 1UL << 27UL )
103 #define portNVIC_PEND_SYSTICK_CLEAR_BIT           ( 1UL << 25UL )
104 
105 /* Constants used to detect Cortex-M7 r0p0 and r0p1 cores, and ensure
106  * that a work around is active for errata 837070. */
107 #define portCPUID                                 ( *( ( volatile uint32_t * ) 0xE000ed00 ) )
108 #define portCORTEX_M7_r0p1_ID                     ( 0x410FC271UL )
109 #define portCORTEX_M7_r0p0_ID                     ( 0x410FC270UL )
110 
111 #define portMIN_INTERRUPT_PRIORITY                ( 255UL )
112 #define portNVIC_PENDSV_PRI                       ( ( ( uint32_t ) portMIN_INTERRUPT_PRIORITY ) << 16UL )
113 #define portNVIC_SYSTICK_PRI                      ( ( ( uint32_t ) portMIN_INTERRUPT_PRIORITY ) << 24UL )
114 
115 /* Constants used to check the installation of the FreeRTOS interrupt handlers. */
116 #define portSCB_VTOR_REG                          ( *( ( portISR_t ** ) 0xE000ED08 ) )
117 #define portVECTOR_INDEX_SVC                      ( 11 )
118 #define portVECTOR_INDEX_PENDSV                   ( 14 )
119 
120 /* Constants required to check the validity of an interrupt priority. */
121 #define portFIRST_USER_INTERRUPT_NUMBER           ( 16 )
122 #define portNVIC_IP_REGISTERS_OFFSET_16           ( 0xE000E3F0 )
123 #define portAIRCR_REG                             ( *( ( volatile uint32_t * ) 0xE000ED0C ) )
124 #define portMAX_8_BIT_VALUE                       ( ( uint8_t ) 0xff )
125 #define portTOP_BIT_OF_BYTE                       ( ( uint8_t ) 0x80 )
126 #define portMAX_PRIGROUP_BITS                     ( ( uint8_t ) 7 )
127 #define portPRIORITY_GROUP_MASK                   ( 0x07UL << 8UL )
128 #define portPRIGROUP_SHIFT                        ( 8UL )
129 
130 /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
131 #define portVECTACTIVE_MASK                       ( 0xFFUL )
132 
133 /* Constants required to manipulate the VFP. */
134 #define portFPCCR                                 ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
135 #define portASPEN_AND_LSPEN_BITS                  ( 0x3UL << 30UL )
136 
137 /* Constants required to set up the initial stack. */
138 #define portINITIAL_XPSR                          ( 0x01000000 )
139 #define portINITIAL_EXC_RETURN                    ( 0xfffffffd )
140 #define portINITIAL_CONTROL_IF_UNPRIVILEGED       ( 0x03 )
141 #define portINITIAL_CONTROL_IF_PRIVILEGED         ( 0x02 )
142 
143 /* Constants used during system call enter and exit. */
144 #define portPSR_STACK_PADDING_MASK                ( 1UL << 9UL )
145 #define portEXC_RETURN_STACK_FRAME_TYPE_MASK      ( 1UL << 4UL )
146 
147 /* Offsets in the stack to the parameters when inside the SVC handler. */
148 #define portOFFSET_TO_LR                          ( 5 )
149 #define portOFFSET_TO_PC                          ( 6 )
150 #define portOFFSET_TO_PSR                         ( 7 )
151 
152 /* The systick is a 24-bit counter. */
153 #define portMAX_24_BIT_NUMBER                     ( 0xffffffUL )
154 
155 /* A fiddle factor to estimate the number of SysTick counts that would have
156  * occurred while the SysTick counter is stopped during tickless idle
157  * calculations. */
158 #define portMISSED_COUNTS_FACTOR                  ( 45UL )
159 
160 /* For strict compliance with the Cortex-M spec the task start address should
161  * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
162 #define portSTART_ADDRESS_MASK                    ( ( StackType_t ) 0xfffffffeUL )
163 
164 /* Does addr lie within [start, end] address range? */
165 #define portIS_ADDRESS_WITHIN_RANGE( addr, start, end ) \
166     ( ( ( addr ) >= ( start ) ) && ( ( addr ) <= ( end ) ) )
167 
168 /* Is the access request satisfied by the available permissions? */
169 #define portIS_AUTHORIZED( accessRequest, permissions ) \
170     ( ( ( permissions ) & ( accessRequest ) ) == accessRequest )
171 
172 /* Max value that fits in a uint32_t type. */
173 #define portUINT32_MAX    ( ~( ( uint32_t ) 0 ) )
174 
175 /* Check if adding a and b will result in overflow. */
176 #define portADD_UINT32_WILL_OVERFLOW( a, b )    ( ( a ) > ( portUINT32_MAX - ( b ) ) )
177 /*-----------------------------------------------------------*/
178 
179 /*
180  * Configure a number of standard MPU regions that are used by all tasks.
181  */
182 static void prvSetupMPU( void ) PRIVILEGED_FUNCTION;
183 
184 /*
185  * Return the smallest MPU region size that a given number of bytes will fit
186  * into.  The region size is returned as the value that should be programmed
187  * into the region attribute register for that region.
188  */
189 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION;
190 
191 /*
192  * Setup the timer to generate the tick interrupts.  The implementation in this
193  * file is weak to allow application writers to change the timer used to
194  * generate the tick interrupt.
195  */
196 void vPortSetupTimerInterrupt( void );
197 
198 /*
199  * Exception handlers.
200  */
201 void xPortSysTickHandler( void ) PRIVILEGED_FUNCTION;
202 
203 /*
204  * Start first task is a separate function so it can be tested in isolation.
205  */
206 extern void vPortStartFirstTask( void ) PRIVILEGED_FUNCTION;
207 
208 /*
209  * Turn the VFP on.
210  */
211 extern void vPortEnableVFP( void );
212 
213 /*
214  * The C portion of the SVC handler.
215  */
216 void vPortSVCHandler_C( uint32_t * pulParam ) PRIVILEGED_FUNCTION;
217 
218 /*
219  * Called from the SVC handler used to start the scheduler.
220  */
221 extern void vPortRestoreContextOfFirstTask( void ) PRIVILEGED_FUNCTION;
222 
223 /**
224  * @brief Enter critical section.
225  */
226 #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
227     void vPortEnterCritical( void ) FREERTOS_SYSTEM_CALL;
228 #else
229     void vPortEnterCritical( void ) PRIVILEGED_FUNCTION;
230 #endif
231 
232 /**
233  * @brief Exit from critical section.
234  */
235 #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
236     void vPortExitCritical( void ) FREERTOS_SYSTEM_CALL;
237 #else
238     void vPortExitCritical( void ) PRIVILEGED_FUNCTION;
239 #endif
240 
241 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
242 
243 /**
244  * @brief Sets up the system call stack so that upon returning from
245  * SVC, the system call stack is used.
246  *
247  * @param pulTaskStack The current SP when the SVC was raised.
248  * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler.
249  * @param ucSystemCallNumber The system call number of the system call.
250  */
251     void vSystemCallEnter( uint32_t * pulTaskStack,
252                            uint32_t ulLR,
253                            uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION;
254 
255 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
256 
257 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
258 
259 /**
260  * @brief Raise SVC for exiting from a system call.
261  */
262     void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
263 
264 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
265 
266 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
267 
268 /**
269  * @brief Sets up the task stack so that upon returning from
270  * SVC, the task stack is used again.
271  *
272  * @param pulSystemCallStack The current SP when the SVC was raised.
273  * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler.
274  */
275     void vSystemCallExit( uint32_t * pulSystemCallStack,
276                           uint32_t ulLR ) PRIVILEGED_FUNCTION;
277 
278 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
279 
280 /**
281  * @brief Checks whether or not the calling task is privileged.
282  *
283  * @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
284  */
285 BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
286 
287 /**
288  * @brief Make a task unprivileged.
289  */
290 void vPortSwitchToUserMode( void );
291 
292 /*
293  * FreeRTOS handlers implemented in assembly.
294  */
295 extern void vPortSVCHandler( void ) PRIVILEGED_FUNCTION;
296 extern void xPortPendSVHandler( void ) PRIVILEGED_FUNCTION;
297 /*-----------------------------------------------------------*/
298 
299 /* Each task maintains its own interrupt status in the critical nesting
300  * variable. */
301 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
302 
303 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
304 
305 /*
306  * This variable is set to pdTRUE when the scheduler is started.
307  */
308     PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE;
309 
310 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
311 
312 /*
313  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
314  * FreeRTOS API functions are not called from interrupts that have been assigned
315  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
316  */
317 #if ( configASSERT_DEFINED == 1 )
318     static uint8_t ucMaxSysCallPriority = 0;
319     static uint32_t ulMaxPRIGROUPValue = 0;
320     static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
321 #endif /* configASSERT_DEFINED */
322 
323 /*-----------------------------------------------------------*/
324 
325 /*
326  * See header file for description.
327  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters,BaseType_t xRunPrivileged,xMPU_SETTINGS * xMPUSettings)328 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
329                                      TaskFunction_t pxCode,
330                                      void * pvParameters,
331                                      BaseType_t xRunPrivileged,
332                                      xMPU_SETTINGS * xMPUSettings )
333 {
334     if( xRunPrivileged == pdTRUE )
335     {
336         xMPUSettings->ulTaskFlags |= portTASK_IS_PRIVILEGED_FLAG;
337         xMPUSettings->ulContext[ 0 ] = portINITIAL_CONTROL_IF_PRIVILEGED;
338     }
339     else
340     {
341         xMPUSettings->ulTaskFlags &= ( ~( portTASK_IS_PRIVILEGED_FLAG ) );
342         xMPUSettings->ulContext[ 0 ] = portINITIAL_CONTROL_IF_UNPRIVILEGED;
343     }
344 
345     xMPUSettings->ulContext[ 1 ] = 0x04040404;                                        /* r4. */
346     xMPUSettings->ulContext[ 2 ] = 0x05050505;                                        /* r5. */
347     xMPUSettings->ulContext[ 3 ] = 0x06060606;                                        /* r6. */
348     xMPUSettings->ulContext[ 4 ] = 0x07070707;                                        /* r7. */
349     xMPUSettings->ulContext[ 5 ] = 0x08080808;                                        /* r8. */
350     xMPUSettings->ulContext[ 6 ] = 0x09090909;                                        /* r9. */
351     xMPUSettings->ulContext[ 7 ] = 0x10101010;                                        /* r10. */
352     xMPUSettings->ulContext[ 8 ] = 0x11111111;                                        /* r11. */
353     xMPUSettings->ulContext[ 9 ] = portINITIAL_EXC_RETURN;                            /* EXC_RETURN. */
354 
355     xMPUSettings->ulContext[ 10 ] = ( uint32_t ) ( pxTopOfStack - 8 );                /* PSP with the hardware saved stack. */
356     xMPUSettings->ulContext[ 11 ] = ( uint32_t ) pvParameters;                        /* r0. */
357     xMPUSettings->ulContext[ 12 ] = 0x01010101;                                       /* r1. */
358     xMPUSettings->ulContext[ 13 ] = 0x02020202;                                       /* r2. */
359     xMPUSettings->ulContext[ 14 ] = 0x03030303;                                       /* r3. */
360     xMPUSettings->ulContext[ 15 ] = 0x12121212;                                       /* r12. */
361     xMPUSettings->ulContext[ 16 ] = 0;                                                /* LR. */
362     xMPUSettings->ulContext[ 17 ] = ( ( uint32_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC. */
363     xMPUSettings->ulContext[ 18 ] = portINITIAL_XPSR;                                 /* xPSR. */
364 
365     #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
366     {
367         /* Ensure that the system call stack is double word aligned. */
368         xMPUSettings->xSystemCallStackInfo.pulSystemCallStack = &( xMPUSettings->xSystemCallStackInfo.ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE - 1 ] );
369         xMPUSettings->xSystemCallStackInfo.pulSystemCallStack = ( uint32_t * ) ( ( uint32_t ) ( xMPUSettings->xSystemCallStackInfo.pulSystemCallStack ) &
370                                                                                  ( uint32_t ) ( ~( portBYTE_ALIGNMENT_MASK ) ) );
371 
372         /* This is not NULL only for the duration of a system call. */
373         xMPUSettings->xSystemCallStackInfo.pulTaskStack = NULL;
374     }
375     #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
376 
377     return &( xMPUSettings->ulContext[ 19 ] );
378 }
379 /*-----------------------------------------------------------*/
380 
vPortSVCHandler_C(uint32_t * pulParam)381 void vPortSVCHandler_C( uint32_t * pulParam ) /* PRIVILEGED_FUNCTION */
382 {
383     uint8_t ucSVCNumber;
384     uint32_t ulPC;
385 
386     #if ( ( configUSE_MPU_WRAPPERS_V1 == 1 ) && ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) )
387         extern uint32_t __syscalls_flash_start__[];
388         extern uint32_t __syscalls_flash_end__[];
389     #endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 1 ) && ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) ) */
390 
391     /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
392      * argument (r0) is pulParam[ 0 ]. */
393     ulPC = pulParam[ portOFFSET_TO_PC ];
394     ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
395 
396     switch( ucSVCNumber )
397     {
398         case portSVC_START_SCHEDULER:
399             vPortRestoreContextOfFirstTask();
400             break;
401 
402         case portSVC_YIELD:
403             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
404 
405             /* Barriers are normally not required
406              * but do ensure the code is completely
407              * within the specified behaviour for the
408              * architecture. */
409             __asm volatile ( "dsb" ::: "memory" );
410             __asm volatile ( "isb" );
411 
412             break;
413 
414     #if ( configUSE_MPU_WRAPPERS_V1 == 1 )
415         #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
416             case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the
417                                            * svc was raised from any of the
418                                            * system calls. */
419 
420                 if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
421                     ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
422                 {
423                     __asm volatile
424                     (
425                         "   mrs r1, control     \n" /* Obtain current control value. */
426                         "   bic r1, r1, #1      \n" /* Set privilege bit. */
427                         "   msr control, r1     \n" /* Write back new control value. */
428                         ::: "r1", "memory"
429                     );
430                 }
431 
432                 break;
433         #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
434             case portSVC_RAISE_PRIVILEGE:
435                 __asm volatile
436                 (
437                     "   mrs r1, control     \n" /* Obtain current control value. */
438                     "   bic r1, r1, #1      \n" /* Set privilege bit. */
439                     "   msr control, r1     \n" /* Write back new control value. */
440                     ::: "r1", "memory"
441                 );
442                 break;
443         #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
444     #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 1 ) */
445 
446         default: /* Unknown SVC call. */
447             break;
448     }
449 }
450 /*-----------------------------------------------------------*/
451 
452 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
453 
vSystemCallEnter(uint32_t * pulTaskStack,uint32_t ulLR,uint8_t ucSystemCallNumber)454     void vSystemCallEnter( uint32_t * pulTaskStack,
455                            uint32_t ulLR,
456                            uint8_t ucSystemCallNumber ) /* PRIVILEGED_FUNCTION */
457     {
458         extern TaskHandle_t pxCurrentTCB;
459         extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ];
460         xMPU_SETTINGS * pxMpuSettings;
461         uint32_t * pulSystemCallStack;
462         uint32_t ulStackFrameSize, ulSystemCallLocation, i;
463 
464         #if defined( __ARMCC_VERSION )
465             /* Declaration when these variable are defined in code instead of being
466              * exported from linker scripts. */
467             extern uint32_t * __syscalls_flash_start__;
468             extern uint32_t * __syscalls_flash_end__;
469         #else
470             /* Declaration when these variable are exported from linker scripts. */
471             extern uint32_t __syscalls_flash_start__[];
472             extern uint32_t __syscalls_flash_end__[];
473         #endif /* #if defined( __ARMCC_VERSION ) */
474 
475         ulSystemCallLocation = pulTaskStack[ portOFFSET_TO_PC ];
476         pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
477 
478         /* Checks:
479          * 1. SVC is raised from the system call section (i.e. application is
480          *    not raising SVC directly).
481          * 2. pxMpuSettings->xSystemCallStackInfo.pulTaskStack must be NULL as
482          *    it is non-NULL only during the execution of a system call (i.e.
483          *    between system call enter and exit).
484          * 3. System call is not for a kernel API disabled by the configuration
485          *    in FreeRTOSConfig.h.
486          * 4. We do not need to check that ucSystemCallNumber is within range
487          *    because the assembly SVC handler checks that before calling
488          *    this function.
489          */
490         if( ( ulSystemCallLocation >= ( uint32_t ) __syscalls_flash_start__ ) &&
491             ( ulSystemCallLocation <= ( uint32_t ) __syscalls_flash_end__ ) &&
492             ( pxMpuSettings->xSystemCallStackInfo.pulTaskStack == NULL ) &&
493             ( uxSystemCallImplementations[ ucSystemCallNumber ] != ( UBaseType_t ) 0 ) )
494         {
495             pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack;
496 
497             if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL )
498             {
499                 /* Extended frame i.e. FPU in use. */
500                 ulStackFrameSize = 26;
501                 __asm volatile (
502                     " vpush {s0}         \n" /* Trigger lazy stacking. */
503                     " vpop  {s0}         \n" /* Nullify the affect of the above instruction. */
504                     ::: "memory"
505                     );
506             }
507             else
508             {
509                 /* Standard frame i.e. FPU not in use. */
510                 ulStackFrameSize = 8;
511             }
512 
513             /* Make space on the system call stack for the stack frame. */
514             pulSystemCallStack = pulSystemCallStack - ulStackFrameSize;
515 
516             /* Copy the stack frame. */
517             for( i = 0; i < ulStackFrameSize; i++ )
518             {
519                 pulSystemCallStack[ i ] = pulTaskStack[ i ];
520             }
521 
522             /* Use the pulSystemCallStack in thread mode. */
523             __asm volatile ( "msr psp, %0" : : "r" ( pulSystemCallStack ) );
524 
525             /* Raise the privilege for the duration of the system call. */
526             __asm volatile (
527                 " mrs r1, control     \n" /* Obtain current control value. */
528                 " bic r1, #1          \n" /* Clear nPRIV bit. */
529                 " msr control, r1     \n" /* Write back new control value. */
530                 ::: "r1", "memory"
531                 );
532 
533             /* Remember the location where we should copy the stack frame when we exit from
534              * the system call. */
535             pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize;
536 
537             /* Store the value of the Link Register before the SVC was raised.
538              * It contains the address of the caller of the System Call entry
539              * point (i.e. the caller of the MPU_<API>). We need to restore it
540              * when we exit from the system call. */
541             pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry = pulTaskStack[ portOFFSET_TO_LR ];
542 
543 
544             /* Start executing the system call upon returning from this handler. */
545             pulSystemCallStack[ portOFFSET_TO_PC ] = uxSystemCallImplementations[ ucSystemCallNumber ];
546             /* Raise a request to exit from the system call upon finishing the
547              * system call. */
548             pulSystemCallStack[ portOFFSET_TO_LR ] = ( uint32_t ) vRequestSystemCallExit;
549 
550             /* Record if the hardware used padding to force the stack pointer
551              * to be double word aligned. */
552             if( ( pulTaskStack[ portOFFSET_TO_PSR ] & portPSR_STACK_PADDING_MASK ) == portPSR_STACK_PADDING_MASK )
553             {
554                 pxMpuSettings->ulTaskFlags |= portSTACK_FRAME_HAS_PADDING_FLAG;
555             }
556             else
557             {
558                 pxMpuSettings->ulTaskFlags &= ( ~portSTACK_FRAME_HAS_PADDING_FLAG );
559             }
560 
561             /* We ensure in pxPortInitialiseStack that the system call stack is
562              * double word aligned and therefore, there is no need of padding.
563              * Clear the bit[9] of stacked xPSR. */
564             pulSystemCallStack[ portOFFSET_TO_PSR ] &= ( ~portPSR_STACK_PADDING_MASK );
565         }
566     }
567 
568 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
569 /*-----------------------------------------------------------*/
570 
571 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
572 
vRequestSystemCallExit(void)573     void vRequestSystemCallExit( void ) /* __attribute__( ( naked ) ) PRIVILEGED_FUNCTION */
574     {
575         __asm volatile ( "svc %0 \n" ::"i" ( portSVC_SYSTEM_CALL_EXIT ) : "memory" );
576     }
577 
578 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
579 /*-----------------------------------------------------------*/
580 
581 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
582 
vSystemCallExit(uint32_t * pulSystemCallStack,uint32_t ulLR)583     void vSystemCallExit( uint32_t * pulSystemCallStack,
584                           uint32_t ulLR ) /* PRIVILEGED_FUNCTION */
585     {
586         extern TaskHandle_t pxCurrentTCB;
587         xMPU_SETTINGS * pxMpuSettings;
588         uint32_t * pulTaskStack;
589         uint32_t ulStackFrameSize, ulSystemCallLocation, i;
590 
591         #if defined( __ARMCC_VERSION )
592             /* Declaration when these variable are defined in code instead of being
593              * exported from linker scripts. */
594             extern uint32_t * __privileged_functions_start__;
595             extern uint32_t * __privileged_functions_end__;
596         #else
597             /* Declaration when these variable are exported from linker scripts. */
598             extern uint32_t __privileged_functions_start__[];
599             extern uint32_t __privileged_functions_end__[];
600         #endif /* #if defined( __ARMCC_VERSION ) */
601 
602         ulSystemCallLocation = pulSystemCallStack[ portOFFSET_TO_PC ];
603         pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
604 
605         /* Checks:
606          * 1. SVC is raised from the privileged code (i.e. application is not
607          *    raising SVC directly). This SVC is only raised from
608          *    vRequestSystemCallExit which is in the privileged code section.
609          * 2. pxMpuSettings->xSystemCallStackInfo.pulTaskStack must not be NULL -
610          *    this means that we previously entered a system call and the
611          *    application is not attempting to exit without entering a system
612          *    call.
613          */
614         if( ( ulSystemCallLocation >= ( uint32_t ) __privileged_functions_start__ ) &&
615             ( ulSystemCallLocation <= ( uint32_t ) __privileged_functions_end__ ) &&
616             ( pxMpuSettings->xSystemCallStackInfo.pulTaskStack != NULL ) )
617         {
618             pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack;
619 
620             if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL )
621             {
622                 /* Extended frame i.e. FPU in use. */
623                 ulStackFrameSize = 26;
624                 __asm volatile (
625                     " vpush {s0}         \n" /* Trigger lazy stacking. */
626                     " vpop  {s0}         \n" /* Nullify the affect of the above instruction. */
627                     ::: "memory"
628                     );
629             }
630             else
631             {
632                 /* Standard frame i.e. FPU not in use. */
633                 ulStackFrameSize = 8;
634             }
635 
636             /* Make space on the task stack for the stack frame. */
637             pulTaskStack = pulTaskStack - ulStackFrameSize;
638 
639             /* Copy the stack frame. */
640             for( i = 0; i < ulStackFrameSize; i++ )
641             {
642                 pulTaskStack[ i ] = pulSystemCallStack[ i ];
643             }
644 
645             /* Use the pulTaskStack in thread mode. */
646             __asm volatile ( "msr psp, %0" : : "r" ( pulTaskStack ) );
647 
648             /* Drop the privilege before returning to the thread mode. */
649             __asm volatile (
650                 " mrs r1, control     \n" /* Obtain current control value. */
651                 " orr r1, #1          \n" /* Set nPRIV bit. */
652                 " msr control, r1     \n" /* Write back new control value. */
653                 ::: "r1", "memory"
654                 );
655 
656             /* Return to the caller of the System Call entry point (i.e. the
657              * caller of the MPU_<API>). */
658             pulTaskStack[ portOFFSET_TO_PC ] = pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry;
659             /* Ensure that LR has a valid value.*/
660             pulTaskStack[ portOFFSET_TO_LR ] = pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry;
661 
662             /* If the hardware used padding to force the stack pointer
663              * to be double word aligned, set the stacked xPSR bit[9],
664              * otherwise clear it. */
665             if( ( pxMpuSettings->ulTaskFlags & portSTACK_FRAME_HAS_PADDING_FLAG ) == portSTACK_FRAME_HAS_PADDING_FLAG )
666             {
667                 pulTaskStack[ portOFFSET_TO_PSR ] |= portPSR_STACK_PADDING_MASK;
668             }
669             else
670             {
671                 pulTaskStack[ portOFFSET_TO_PSR ] &= ( ~portPSR_STACK_PADDING_MASK );
672             }
673 
674             /* This is not NULL only for the duration of the system call. */
675             pxMpuSettings->xSystemCallStackInfo.pulTaskStack = NULL;
676         }
677     }
678 
679 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
680 /*-----------------------------------------------------------*/
681 
xPortIsTaskPrivileged(void)682 BaseType_t xPortIsTaskPrivileged( void ) /* PRIVILEGED_FUNCTION */
683 {
684     BaseType_t xTaskIsPrivileged = pdFALSE;
685     const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
686 
687     if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
688     {
689         xTaskIsPrivileged = pdTRUE;
690     }
691 
692     return xTaskIsPrivileged;
693 }
694 /*-----------------------------------------------------------*/
695 
vPortSwitchToUserMode(void)696 void vPortSwitchToUserMode( void )
697 {
698     /* Load the current task's MPU settings from its TCB. */
699     xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL );
700 
701     /* Mark the task as unprivileged. */
702     xTaskMpuSettings->ulTaskFlags &= ( ~( portTASK_IS_PRIVILEGED_FLAG ) );
703 
704     /* Lower the processor's privilege level. */
705     vResetPrivilege();
706 }
707 /*-----------------------------------------------------------*/
708 
709 /*
710  * See header file for description.
711  */
xPortStartScheduler(void)712 BaseType_t xPortStartScheduler( void )
713 {
714     /* Errata 837070 workaround must only be enabled on Cortex-M7 r0p0
715      * and r0p1 cores. */
716     #if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )
717         configASSERT( ( portCPUID == portCORTEX_M7_r0p1_ID ) || ( portCPUID == portCORTEX_M7_r0p0_ID ) );
718     #else
719 
720         /* When using this port on a Cortex-M7 r0p0 or r0p1 core, define
721          * configENABLE_ERRATA_837070_WORKAROUND to 1 in your
722          * FreeRTOSConfig.h. */
723         configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
724         configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
725     #endif
726 
727     /* An application can install FreeRTOS interrupt handlers in one of the
728      * following ways:
729      * 1. Direct Routing - Install the functions vPortSVCHandler and
730      *    xPortPendSVHandler for SVCall and PendSV interrupts respectively.
731      * 2. Indirect Routing - Install separate handlers for SVCall and PendSV
732      *    interrupts and route program control from those handlers to
733      *    vPortSVCHandler and xPortPendSVHandler functions.
734      *
735      * Applications that use Indirect Routing must set
736      * configCHECK_HANDLER_INSTALLATION to 0 in their FreeRTOSConfig.h. Direct
737      * routing, which is validated here when configCHECK_HANDLER_INSTALLATION
738      * is 1, should be preferred when possible. */
739     #if ( configCHECK_HANDLER_INSTALLATION == 1 )
740     {
741         const portISR_t * const pxVectorTable = portSCB_VTOR_REG;
742 
743         /* Validate that the application has correctly installed the FreeRTOS
744          * handlers for SVCall and PendSV interrupts. We do not check the
745          * installation of the SysTick handler because the application may
746          * choose to drive the RTOS tick using a timer other than the SysTick
747          * timer by overriding the weak function vPortSetupTimerInterrupt().
748          *
749          * Assertion failures here indicate incorrect installation of the
750          * FreeRTOS handlers. For help installing the FreeRTOS handlers, see
751          * https://www.FreeRTOS.org/FAQHelp.html.
752          *
753          * Systems with a configurable address for the interrupt vector table
754          * can also encounter assertion failures or even system faults here if
755          * VTOR is not set correctly to point to the application's vector table. */
756         configASSERT( pxVectorTable[ portVECTOR_INDEX_SVC ] == vPortSVCHandler );
757         configASSERT( pxVectorTable[ portVECTOR_INDEX_PENDSV ] == xPortPendSVHandler );
758     }
759     #endif /* configCHECK_HANDLER_INSTALLATION */
760 
761     #if ( configASSERT_DEFINED == 1 )
762     {
763         volatile uint8_t ucOriginalPriority;
764         volatile uint32_t ulImplementedPrioBits = 0;
765         volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
766         volatile uint8_t ucMaxPriorityValue;
767 
768         /* Determine the maximum priority from which ISR safe FreeRTOS API
769          * functions can be called.  ISR safe functions are those that end in
770          * "FromISR".  FreeRTOS maintains separate thread and ISR API functions to
771          * ensure interrupt entry is as fast and simple as possible.
772          *
773          * Save the interrupt priority value that is about to be clobbered. */
774         ucOriginalPriority = *pucFirstUserPriorityRegister;
775 
776         /* Determine the number of priority bits available.  First write to all
777          * possible bits. */
778         *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
779 
780         /* Read the value back to see how many bits stuck. */
781         ucMaxPriorityValue = *pucFirstUserPriorityRegister;
782 
783         /* Use the same mask on the maximum system call priority. */
784         ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
785 
786         /* Check that the maximum system call priority is nonzero after
787          * accounting for the number of priority bits supported by the
788          * hardware. A priority of 0 is invalid because setting the BASEPRI
789          * register to 0 unmasks all interrupts, and interrupts with priority 0
790          * cannot be masked using BASEPRI.
791          * See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
792         configASSERT( ucMaxSysCallPriority );
793 
794         /* Check that the bits not implemented in hardware are zero in
795          * configMAX_SYSCALL_INTERRUPT_PRIORITY. */
796         configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
797 
798         /* Calculate the maximum acceptable priority group value for the number
799          * of bits read back. */
800 
801         while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
802         {
803             ulImplementedPrioBits++;
804             ucMaxPriorityValue <<= ( uint8_t ) 0x01;
805         }
806 
807         if( ulImplementedPrioBits == 8 )
808         {
809             /* When the hardware implements 8 priority bits, there is no way for
810              * the software to configure PRIGROUP to not have sub-priorities. As
811              * a result, the least significant bit is always used for sub-priority
812              * and there are 128 preemption priorities and 2 sub-priorities.
813              *
814              * This may cause some confusion in some cases - for example, if
815              * configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
816              * priority interrupts will be masked in Critical Sections as those
817              * are at the same preemption priority. This may appear confusing as
818              * 4 is higher (numerically lower) priority than
819              * configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
820              * have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
821              * to 4, this confusion does not happen and the behaviour remains the same.
822              *
823              * The following assert ensures that the sub-priority bit in the
824              * configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
825              * confusion. */
826             configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
827             ulMaxPRIGROUPValue = 0;
828         }
829         else
830         {
831             ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
832         }
833 
834         /* Shift the priority group value back to its position within the AIRCR
835          * register. */
836         ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
837         ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
838 
839         /* Restore the clobbered interrupt priority register to its original
840          * value. */
841         *pucFirstUserPriorityRegister = ucOriginalPriority;
842     }
843     #endif /* configASSERT_DEFINED */
844 
845     /* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
846      * the highest priority. */
847     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
848     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
849     portNVIC_SHPR2_REG = 0;
850 
851     /* Configure the regions in the MPU that are common to all tasks. */
852     prvSetupMPU();
853 
854     /* Start the timer that generates the tick ISR.  Interrupts are disabled
855      * here already. */
856     vPortSetupTimerInterrupt();
857 
858     /* Initialise the critical nesting count ready for the first task. */
859     uxCriticalNesting = 0;
860 
861     #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
862     {
863         xSchedulerRunning = pdTRUE;
864     }
865     #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
866 
867     /* Ensure the VFP is enabled - it should be anyway. */
868     vPortEnableVFP();
869 
870     /* Lazy save always. */
871     *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
872 
873     /* Start the first task. */
874     vPortStartFirstTask();
875 
876     /* Should not get here! */
877     return 0;
878 }
879 /*-----------------------------------------------------------*/
880 
vPortEndScheduler(void)881 void vPortEndScheduler( void )
882 {
883     /* Not implemented in ports where there is nothing to return to.
884      * Artificially force an assert. */
885     configASSERT( uxCriticalNesting == 1000UL );
886 }
887 /*-----------------------------------------------------------*/
888 
vPortEnterCritical(void)889 void vPortEnterCritical( void )
890 {
891     #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
892         if( portIS_PRIVILEGED() == pdFALSE )
893         {
894             portRAISE_PRIVILEGE();
895             portMEMORY_BARRIER();
896 
897             portDISABLE_INTERRUPTS();
898             uxCriticalNesting++;
899 
900             /* This is not the interrupt safe version of the enter critical function so
901              * assert() if it is being called from an interrupt context.  Only API
902              * functions that end in "FromISR" can be used in an interrupt.  Only assert if
903              * the critical nesting count is 1 to protect against recursive calls if the
904              * assert function also uses a critical section. */
905             if( uxCriticalNesting == 1 )
906             {
907                 configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
908             }
909 
910             portMEMORY_BARRIER();
911 
912             portRESET_PRIVILEGE();
913             portMEMORY_BARRIER();
914         }
915         else
916         {
917             portDISABLE_INTERRUPTS();
918             uxCriticalNesting++;
919 
920             /* This is not the interrupt safe version of the enter critical function so
921              * assert() if it is being called from an interrupt context.  Only API
922              * functions that end in "FromISR" can be used in an interrupt.  Only assert if
923              * the critical nesting count is 1 to protect against recursive calls if the
924              * assert function also uses a critical section. */
925             if( uxCriticalNesting == 1 )
926             {
927                 configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
928             }
929         }
930     #else /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
931         portDISABLE_INTERRUPTS();
932         uxCriticalNesting++;
933 
934         /* This is not the interrupt safe version of the enter critical function so
935          * assert() if it is being called from an interrupt context.  Only API
936          * functions that end in "FromISR" can be used in an interrupt.  Only assert if
937          * the critical nesting count is 1 to protect against recursive calls if the
938          * assert function also uses a critical section. */
939         if( uxCriticalNesting == 1 )
940         {
941             configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
942         }
943     #endif /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
944 }
945 /*-----------------------------------------------------------*/
946 
vPortExitCritical(void)947 void vPortExitCritical( void )
948 {
949     #if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 )
950         if( portIS_PRIVILEGED() == pdFALSE )
951         {
952             portRAISE_PRIVILEGE();
953             portMEMORY_BARRIER();
954 
955             configASSERT( uxCriticalNesting );
956             uxCriticalNesting--;
957 
958             if( uxCriticalNesting == 0 )
959             {
960                 portENABLE_INTERRUPTS();
961             }
962 
963             portMEMORY_BARRIER();
964 
965             portRESET_PRIVILEGE();
966             portMEMORY_BARRIER();
967         }
968         else
969         {
970             configASSERT( uxCriticalNesting );
971             uxCriticalNesting--;
972 
973             if( uxCriticalNesting == 0 )
974             {
975                 portENABLE_INTERRUPTS();
976             }
977         }
978     #else /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
979         configASSERT( uxCriticalNesting );
980         uxCriticalNesting--;
981 
982         if( uxCriticalNesting == 0 )
983         {
984             portENABLE_INTERRUPTS();
985         }
986     #endif /* if ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) */
987 }
988 /*-----------------------------------------------------------*/
989 
xPortSysTickHandler(void)990 void xPortSysTickHandler( void )
991 {
992     /* The SysTick runs at the lowest interrupt priority, so when this interrupt
993      * executes all interrupts must be unmasked.  There is therefore no need to
994      * save and then restore the interrupt mask value as its value is already
995      * known. */
996     portDISABLE_INTERRUPTS();
997     traceISR_ENTER();
998     {
999         /* Increment the RTOS tick. */
1000         if( xTaskIncrementTick() != pdFALSE )
1001         {
1002             traceISR_EXIT_TO_SCHEDULER();
1003 
1004             /* A context switch is required.  Context switching is performed in
1005              * the PendSV interrupt.  Pend the PendSV interrupt. */
1006             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
1007         }
1008         else
1009         {
1010             traceISR_EXIT();
1011         }
1012     }
1013     portENABLE_INTERRUPTS();
1014 }
1015 /*-----------------------------------------------------------*/
1016 
1017 /*
1018  * Setup the systick timer to generate the tick interrupts at the required
1019  * frequency.
1020  */
vPortSetupTimerInterrupt(void)1021 __weak void vPortSetupTimerInterrupt( void )
1022 {
1023     /* Stop and clear the SysTick. */
1024     portNVIC_SYSTICK_CTRL_REG = 0UL;
1025     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
1026 
1027     /* Configure SysTick to interrupt at the requested rate. */
1028     portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
1029     portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
1030 }
1031 /*-----------------------------------------------------------*/
1032 
prvSetupMPU(void)1033 static void prvSetupMPU( void )
1034 {
1035     extern uint32_t __privileged_functions_start__[];
1036     extern uint32_t __privileged_functions_end__[];
1037     extern uint32_t __FLASH_segment_start__[];
1038     extern uint32_t __FLASH_segment_end__[];
1039     extern uint32_t __privileged_data_start__[];
1040     extern uint32_t __privileged_data_end__[];
1041 
1042     /* The only permitted number of regions are 8 or 16. */
1043     configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) );
1044 
1045     /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */
1046     configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );
1047 
1048     /* Check the expected MPU is present. */
1049     if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
1050     {
1051         /* First setup the unprivileged flash for unprivileged read only access. */
1052         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
1053                                           ( portMPU_REGION_VALID ) |
1054                                           ( portUNPRIVILEGED_FLASH_REGION );
1055 
1056         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |
1057                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
1058                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |
1059                                        ( portMPU_REGION_ENABLE );
1060 
1061         /* Setup the privileged flash for privileged only access.  This is where
1062          * the kernel code is placed. */
1063         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */
1064                                           ( portMPU_REGION_VALID ) |
1065                                           ( portPRIVILEGED_FLASH_REGION );
1066 
1067         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |
1068                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
1069                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) |
1070                                        ( portMPU_REGION_ENABLE );
1071 
1072         /* Setup the privileged data RAM region.  This is where the kernel data
1073          * is placed. */
1074         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
1075                                           ( portMPU_REGION_VALID ) |
1076                                           ( portPRIVILEGED_RAM_REGION );
1077 
1078         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
1079                                        ( portMPU_REGION_EXECUTE_NEVER ) |
1080                                        ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
1081                                        prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
1082                                        ( portMPU_REGION_ENABLE );
1083 
1084         /* By default allow everything to access the general peripherals.  The
1085          * system peripherals and registers are protected. */
1086         portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
1087                                           ( portMPU_REGION_VALID ) |
1088                                           ( portGENERAL_PERIPHERALS_REGION );
1089 
1090         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) |
1091                                        ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) |
1092                                        ( portMPU_REGION_ENABLE );
1093 
1094         /* Enable the memory fault exception. */
1095         portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;
1096 
1097         /* Enable the MPU with the background region configured. */
1098         portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );
1099     }
1100 }
1101 /*-----------------------------------------------------------*/
1102 
prvGetMPURegionSizeSetting(uint32_t ulActualSizeInBytes)1103 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
1104 {
1105     uint32_t ulRegionSize, ulReturnValue = 4;
1106 
1107     /* 32 is the smallest region size, 31 is the largest valid value for
1108      * ulReturnValue. */
1109     for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
1110     {
1111         if( ulActualSizeInBytes <= ulRegionSize )
1112         {
1113             break;
1114         }
1115         else
1116         {
1117             ulReturnValue++;
1118         }
1119     }
1120 
1121     /* Shift the code by one before returning so it can be written directly
1122      * into the the correct bit position of the attribute register. */
1123     return( ulReturnValue << 1UL );
1124 }
1125 /*-----------------------------------------------------------*/
1126 
vPortStoreTaskMPUSettings(xMPU_SETTINGS * xMPUSettings,const struct xMEMORY_REGION * const xRegions,StackType_t * pxBottomOfStack,configSTACK_DEPTH_TYPE uxStackDepth)1127 void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
1128                                 const struct xMEMORY_REGION * const xRegions,
1129                                 StackType_t * pxBottomOfStack,
1130                                 configSTACK_DEPTH_TYPE uxStackDepth )
1131 {
1132     extern uint32_t __SRAM_segment_start__[];
1133     extern uint32_t __SRAM_segment_end__[];
1134     extern uint32_t __privileged_data_start__[];
1135     extern uint32_t __privileged_data_end__[];
1136     int32_t lIndex;
1137     uint32_t ul;
1138 
1139     if( xRegions == NULL )
1140     {
1141         /* No MPU regions are specified so allow access to all RAM. */
1142         xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
1143             ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */
1144             ( portMPU_REGION_VALID ) |
1145             ( portSTACK_REGION );                     /* Region number. */
1146 
1147         xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
1148             ( portMPU_REGION_READ_WRITE ) |
1149             ( portMPU_REGION_EXECUTE_NEVER ) |
1150             ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
1151             ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
1152             ( portMPU_REGION_ENABLE );
1153 
1154         xMPUSettings->xRegionSettings[ 0 ].ulRegionStartAddress = ( uint32_t ) __SRAM_segment_start__;
1155         xMPUSettings->xRegionSettings[ 0 ].ulRegionEndAddress = ( uint32_t ) __SRAM_segment_end__;
1156         xMPUSettings->xRegionSettings[ 0 ].ulRegionPermissions = ( tskMPU_READ_PERMISSION |
1157                                                                    tskMPU_WRITE_PERMISSION );
1158 
1159         /* Invalidate user configurable regions. */
1160         for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
1161         {
1162             xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
1163             xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
1164             xMPUSettings->xRegionSettings[ ul ].ulRegionStartAddress = 0UL;
1165             xMPUSettings->xRegionSettings[ ul ].ulRegionEndAddress = 0UL;
1166             xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = 0UL;
1167         }
1168     }
1169     else
1170     {
1171         /* This function is called automatically when the task is created - in
1172          * which case the stack region parameters will be valid.  At all other
1173          * times the stack parameters will not be valid and it is assumed that the
1174          * stack region has already been configured. */
1175         if( uxStackDepth > 0 )
1176         {
1177             /* Define the region that allows access to the stack. */
1178             xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
1179                 ( ( uint32_t ) pxBottomOfStack ) |
1180                 ( portMPU_REGION_VALID ) |
1181                 ( portSTACK_REGION ); /* Region number. */
1182 
1183             xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
1184                 ( portMPU_REGION_READ_WRITE ) |
1185                 ( portMPU_REGION_EXECUTE_NEVER ) |
1186                 ( prvGetMPURegionSizeSetting( uxStackDepth * ( configSTACK_DEPTH_TYPE ) sizeof( StackType_t ) ) ) |
1187                 ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
1188                 ( portMPU_REGION_ENABLE );
1189 
1190             xMPUSettings->xRegionSettings[ 0 ].ulRegionStartAddress = ( uint32_t ) pxBottomOfStack;
1191             xMPUSettings->xRegionSettings[ 0 ].ulRegionEndAddress = ( uint32_t ) ( ( uint32_t ) ( pxBottomOfStack ) +
1192                                                                                    ( uxStackDepth * ( configSTACK_DEPTH_TYPE ) sizeof( StackType_t ) ) - 1UL );
1193             xMPUSettings->xRegionSettings[ 0 ].ulRegionPermissions = ( tskMPU_READ_PERMISSION |
1194                                                                        tskMPU_WRITE_PERMISSION );
1195         }
1196 
1197         lIndex = 0;
1198 
1199         for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
1200         {
1201             if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
1202             {
1203                 /* Translate the generic region definition contained in
1204                  * xRegions into the CM4 specific MPU settings that are then
1205                  * stored in xMPUSettings. */
1206                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
1207                     ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
1208                     ( portMPU_REGION_VALID ) |
1209                     ( ul - 1UL ); /* Region number. */
1210 
1211                 xMPUSettings->xRegion[ ul ].ulRegionAttribute =
1212                     ( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |
1213                     ( xRegions[ lIndex ].ulParameters ) |
1214                     ( portMPU_REGION_ENABLE );
1215 
1216                 xMPUSettings->xRegionSettings[ ul ].ulRegionStartAddress = ( uint32_t ) xRegions[ lIndex ].pvBaseAddress;
1217                 xMPUSettings->xRegionSettings[ ul ].ulRegionEndAddress = ( uint32_t ) ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress + xRegions[ lIndex ].ulLengthInBytes - 1UL );
1218                 xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = 0UL;
1219 
1220                 if( ( ( xRegions[ lIndex ].ulParameters & portMPU_REGION_READ_ONLY ) == portMPU_REGION_READ_ONLY ) ||
1221                     ( ( xRegions[ lIndex ].ulParameters & portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ) == portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ) )
1222                 {
1223                     xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = tskMPU_READ_PERMISSION;
1224                 }
1225 
1226                 if( ( xRegions[ lIndex ].ulParameters & portMPU_REGION_READ_WRITE ) == portMPU_REGION_READ_WRITE )
1227                 {
1228                     xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = ( tskMPU_READ_PERMISSION | tskMPU_WRITE_PERMISSION );
1229                 }
1230             }
1231             else
1232             {
1233                 /* Invalidate the region. */
1234                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
1235                 xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
1236                 xMPUSettings->xRegionSettings[ ul ].ulRegionStartAddress = 0UL;
1237                 xMPUSettings->xRegionSettings[ ul ].ulRegionEndAddress = 0UL;
1238                 xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = 0UL;
1239             }
1240 
1241             lIndex++;
1242         }
1243     }
1244 }
1245 /*-----------------------------------------------------------*/
1246 
1247 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
1248 
xPortIsAuthorizedToAccessBuffer(const void * pvBuffer,uint32_t ulBufferLength,uint32_t ulAccessRequested)1249     BaseType_t xPortIsAuthorizedToAccessBuffer( const void * pvBuffer,
1250                                                 uint32_t ulBufferLength,
1251                                                 uint32_t ulAccessRequested ) /* PRIVILEGED_FUNCTION */
1252 
1253     {
1254         uint32_t i, ulBufferStartAddress, ulBufferEndAddress;
1255         BaseType_t xAccessGranted = pdFALSE;
1256         const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
1257 
1258         if( xSchedulerRunning == pdFALSE )
1259         {
1260             /* Grant access to all the kernel objects before the scheduler
1261              * is started. It is necessary because there is no task running
1262              * yet and therefore, we cannot use the permissions of any
1263              * task. */
1264             xAccessGranted = pdTRUE;
1265         }
1266         else if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
1267         {
1268             xAccessGranted = pdTRUE;
1269         }
1270         else
1271         {
1272             if( portADD_UINT32_WILL_OVERFLOW( ( ( uint32_t ) pvBuffer ), ( ulBufferLength - 1UL ) ) == pdFALSE )
1273             {
1274                 ulBufferStartAddress = ( uint32_t ) pvBuffer;
1275                 ulBufferEndAddress = ( ( ( uint32_t ) pvBuffer ) + ulBufferLength - 1UL );
1276 
1277                 for( i = 0; i < portTOTAL_NUM_REGIONS_IN_TCB; i++ )
1278                 {
1279                     if( portIS_ADDRESS_WITHIN_RANGE( ulBufferStartAddress,
1280                                                      xTaskMpuSettings->xRegionSettings[ i ].ulRegionStartAddress,
1281                                                      xTaskMpuSettings->xRegionSettings[ i ].ulRegionEndAddress ) &&
1282                         portIS_ADDRESS_WITHIN_RANGE( ulBufferEndAddress,
1283                                                      xTaskMpuSettings->xRegionSettings[ i ].ulRegionStartAddress,
1284                                                      xTaskMpuSettings->xRegionSettings[ i ].ulRegionEndAddress ) &&
1285                         portIS_AUTHORIZED( ulAccessRequested, xTaskMpuSettings->xRegionSettings[ i ].ulRegionPermissions ) )
1286                     {
1287                         xAccessGranted = pdTRUE;
1288                         break;
1289                     }
1290                 }
1291             }
1292         }
1293 
1294         return xAccessGranted;
1295     }
1296 
1297 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
1298 /*-----------------------------------------------------------*/
1299 
1300 
1301 #if ( configASSERT_DEFINED == 1 )
1302 
vPortValidateInterruptPriority(void)1303     void vPortValidateInterruptPriority( void )
1304     {
1305         uint32_t ulCurrentInterrupt;
1306         uint8_t ucCurrentPriority;
1307 
1308         /* Obtain the number of the currently executing interrupt. */
1309         __asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );
1310 
1311         /* Is the interrupt number a user defined interrupt? */
1312         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
1313         {
1314             /* Look up the interrupt's priority. */
1315             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
1316 
1317             /* The following assertion will fail if a service routine (ISR) for
1318              * an interrupt that has been assigned a priority above
1319              * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
1320              * function.  ISR safe FreeRTOS API functions must *only* be called
1321              * from interrupts that have been assigned a priority at or below
1322              * configMAX_SYSCALL_INTERRUPT_PRIORITY.
1323              *
1324              * Numerically low interrupt priority numbers represent logically high
1325              * interrupt priorities, therefore the priority of the interrupt must
1326              * be set to a value equal to or numerically *higher* than
1327              * configMAX_SYSCALL_INTERRUPT_PRIORITY.
1328              *
1329              * Interrupts that  use the FreeRTOS API must not be left at their
1330              * default priority of  zero as that is the highest possible priority,
1331              * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
1332              * and  therefore also guaranteed to be invalid.
1333              *
1334              * FreeRTOS maintains separate thread and ISR API functions to ensure
1335              * interrupt entry is as fast and simple as possible.
1336              *
1337              * The following links provide detailed information:
1338              * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
1339              * https://www.FreeRTOS.org/FAQHelp.html */
1340             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
1341         }
1342 
1343         /* Priority grouping:  The interrupt controller (NVIC) allows the bits
1344          * that define each interrupt's priority to be split between bits that
1345          * define the interrupt's pre-emption priority bits and bits that define
1346          * the interrupt's sub-priority.  For simplicity all bits must be defined
1347          * to be pre-emption priority bits.  The following assertion will fail if
1348          * this is not the case (if some bits represent a sub-priority).
1349          *
1350          * If the application only uses CMSIS libraries for interrupt
1351          * configuration then the correct setting can be achieved on all Cortex-M
1352          * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
1353          * scheduler.  Note however that some vendor specific peripheral libraries
1354          * assume a non-zero priority group setting, in which cases using a value
1355          * of zero will result in unpredictable behaviour. */
1356         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
1357     }
1358 
1359 #endif /* configASSERT_DEFINED */
1360 /*-----------------------------------------------------------*/
1361 
1362 #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
1363 
vPortGrantAccessToKernelObject(TaskHandle_t xInternalTaskHandle,int32_t lInternalIndexOfKernelObject)1364     void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
1365                                          int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1366     {
1367         uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
1368         xMPU_SETTINGS * xTaskMpuSettings;
1369 
1370         ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
1371         ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
1372 
1373         xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
1374 
1375         xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] |= ( 1U << ulAccessControlListEntryBit );
1376     }
1377 
1378 #endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
1379 /*-----------------------------------------------------------*/
1380 
1381 #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
1382 
vPortRevokeAccessToKernelObject(TaskHandle_t xInternalTaskHandle,int32_t lInternalIndexOfKernelObject)1383     void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
1384                                           int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1385     {
1386         uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
1387         xMPU_SETTINGS * xTaskMpuSettings;
1388 
1389         ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
1390         ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
1391 
1392         xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
1393 
1394         xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] &= ~( 1U << ulAccessControlListEntryBit );
1395     }
1396 
1397 #endif /* #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */
1398 /*-----------------------------------------------------------*/
1399 
1400 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
1401 
1402     #if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
1403 
xPortIsAuthorizedToAccessKernelObject(int32_t lInternalIndexOfKernelObject)1404         BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1405         {
1406             uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
1407             BaseType_t xAccessGranted = pdFALSE;
1408             const xMPU_SETTINGS * xTaskMpuSettings;
1409 
1410             if( xSchedulerRunning == pdFALSE )
1411             {
1412                 /* Grant access to all the kernel objects before the scheduler
1413                  * is started. It is necessary because there is no task running
1414                  * yet and therefore, we cannot use the permissions of any
1415                  * task. */
1416                 xAccessGranted = pdTRUE;
1417             }
1418             else
1419             {
1420                 xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
1421 
1422                 ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
1423                 ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
1424 
1425                 if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
1426                 {
1427                     xAccessGranted = pdTRUE;
1428                 }
1429                 else
1430                 {
1431                     if( ( xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] & ( 1U << ulAccessControlListEntryBit ) ) != 0 )
1432                     {
1433                         xAccessGranted = pdTRUE;
1434                     }
1435                 }
1436             }
1437 
1438             return xAccessGranted;
1439         }
1440 
1441     #else /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
1442 
xPortIsAuthorizedToAccessKernelObject(int32_t lInternalIndexOfKernelObject)1443         BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
1444         {
1445             ( void ) lInternalIndexOfKernelObject;
1446 
1447             /* If Access Control List feature is not used, all the tasks have
1448              * access to all the kernel objects. */
1449             return pdTRUE;
1450         }
1451 
1452     #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
1453 
1454 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
1455 /*-----------------------------------------------------------*/
1456