1 /*
2  * FreeRTOS Kernel V11.1.0
3  * Copyright (C) 2024 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 /* Standard includes. */
30 #include <stdint.h>
31 
32 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
33  * all the API functions to use the MPU wrappers. That should only be done when
34  * task.h is included from an application file. */
35 #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
36     #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
37 #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
38 
39 /* Scheduler includes. */
40 #include "FreeRTOS.h"
41 #include "portmacro.h"
42 #include "task.h"
43 #include "mpu_syscall_numbers.h"
44 
45 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
46 
47 /* Max value that fits in a uint32_t type. */
48 #define portUINT32_MAX    ( ~( ( uint32_t ) 0 ) )
49 
50 /* Check if adding a and b will result in overflow. */
51 #define portADD_UINT32_WILL_OVERFLOW( a, b )    ( ( a ) > ( portUINT32_MAX - ( b ) ) )
52 /* ----------------------------------------------------------------------------------- */
53 
54 /**
55  * @brief Variable used to keep track of critical section nesting.
56  *
57  * @ingroup Critical Sections
58  *
59  * This variable is stored as part of the task context and must be initialised
60  * to a non zero value to ensure interrupts don't inadvertently become unmasked
61  * before the scheduler starts. As it is stored as part of the task context, it
62  * will be set to 0 when the first task is started.
63  */
64 PRIVILEGED_DATA volatile UBaseType_t ulCriticalNesting = 0xFFFF;
65 
66 /**
67  * @brief Set to 1 to pend a context switch from an ISR.
68  *
69  * @ingroup Interrupt Management
70  */
71 PRIVILEGED_DATA volatile UBaseType_t ulPortYieldRequired = pdFALSE;
72 
73 /**
74  * @brief Interrupt nesting depth, used to count the number of interrupts to unwind.
75  *
76  * @ingroup Interrupt Management
77  */
78 PRIVILEGED_DATA volatile UBaseType_t ulPortInterruptNesting = 0UL;
79 
80 /**
81  * @brief Variable to track whether or not the scheduler has been started.
82  *
83  * @ingroup Scheduler
84  *
85  * This is the port specific version of the xSchedulerRunning in tasks.c.
86  */
87 PRIVILEGED_DATA static BaseType_t prvPortSchedulerRunning = pdFALSE;
88 
89 /* -------------------------- Private Function Declarations -------------------------- */
90 
91 /**
92  * @brief Determine if the given MPU region settings authorizes the requested
93  * access to the given buffer.
94  *
95  * @ingroup Task Context
96  * @ingroup MPU Control
97  *
98  * @param xTaskMPURegion MPU region settings.
99  * @param ulBufferStart Start address of the given buffer.
100  * @param ulBufferLength Length of the given buffer.
101  * @param ulAccessRequested Access requested.
102  *
103  * @return pdTRUE if MPU region settins authorizes the requested access to the
104  * given buffer, pdFALSE otherwise.
105  */
106 PRIVILEGED_FUNCTION static BaseType_t prvMPURegionAuthorizesBuffer( const xMPU_REGION_REGISTERS * xTaskMPURegion,
107                                                                     const uint32_t ulBufferStart,
108                                                                     const uint32_t ulBufferLength,
109                                                                     const uint32_t ulAccessRequested );
110 
111 /**
112  * @brief Determine the smallest MPU Region Size Encoding for the given MPU
113  * region size.
114  *
115  * @ingroup MPU Control
116  *
117  * @param ulActualMPURegionSize MPU region size in bytes.
118  *
119  * @return The smallest MPU Region Size Encoding for the given MPU region size.
120  */
121 PRIVILEGED_FUNCTION static uint32_t prvGetMPURegionSizeEncoding( uint32_t ulActualMPURegionSize );
122 
123 /**
124  * @brief Set up MPU.
125  *
126  * @ingroup MPU Control
127  */
128 PRIVILEGED_FUNCTION static void prvSetupMPU( void );
129 
130 /* -------------------------- Exported Function Declarations -------------------------- */
131 
132 /**
133  * @brief Enter critical section.
134  *
135  * @ingroup Critical Section
136  */
137 PRIVILEGED_FUNCTION void vPortEnterCritical( void );
138 
139 /**
140  * @brief Exit critical section.
141  *
142  * @ingroup Critical Section
143  */
144 PRIVILEGED_FUNCTION void vPortExitCritical( void );
145 
146 /* ----------------------------------------------------------------------------------- */
147 
148 /**
149  * @brief Setup a FreeRTOS task's initial context.
150  *
151  * @ingroup Task Context
152  *
153  * @param pxTopOfStack Top of stack.
154  * @param pxCode The task function.
155  * @param pvParameters Argument passed to the task function.
156  * @param xRunPrivileged Marks if the task is privileged.
157  * @param xMPUSettings MPU settings of the task.
158  *
159  * @return Location where to restore the task's context from.
160  */
161 /* PRIVILEGED_FUNCTION */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters,BaseType_t xRunPrivileged,xMPU_SETTINGS * xMPUSettings)162 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
163                                      TaskFunction_t pxCode,
164                                      void * pvParameters,
165                                      BaseType_t xRunPrivileged,
166                                      xMPU_SETTINGS * xMPUSettings )
167 {
168     /* Setup the initial context of the task. The context is set exactly as
169      * expected by the portRESTORE_CONTEXT() macro. */
170     UBaseType_t ulIndex = CONTEXT_SIZE - 1U;
171 
172     xSYSTEM_CALL_STACK_INFO * xSysCallInfo = NULL;
173 
174     if( xRunPrivileged == pdTRUE )
175     {
176         xMPUSettings->ulTaskFlags |= portTASK_IS_PRIVILEGED_FLAG;
177         /* Current Program Status Register (CPSR). */
178         xMPUSettings->ulContext[ ulIndex ] = SYS_MODE;
179     }
180     else
181     {
182         xMPUSettings->ulTaskFlags &= ( ~portTASK_IS_PRIVILEGED_FLAG );
183         /* Current Program Status Register (CPSR). */
184         xMPUSettings->ulContext[ ulIndex ] = USER_MODE;
185     }
186 
187     if( ( ( uint32_t ) pxCode & portTHUMB_MODE_ADDRESS ) != 0x0UL )
188     {
189         /* The task will cause the processor to start in THUMB state, set the
190          * Thumb state bit in the CPSR. */
191         xMPUSettings->ulContext[ ulIndex ] |= portTHUMB_MODE_BIT;
192     }
193 
194     ulIndex--;
195 
196     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) pxCode; /* PC. */
197     ulIndex--;
198 
199     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */
200     ulIndex--;
201 
202     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) pxTopOfStack; /* SP. */
203     ulIndex--;
204 
205     /* General Purpose Registers. */
206     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x12121212; /* R12. */
207     ulIndex--;
208     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x11111111; /* R11. */
209     ulIndex--;
210     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x10101010; /* R10. */
211     ulIndex--;
212     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x09090909; /* R9. */
213     ulIndex--;
214     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x08080808; /* R8. */
215     ulIndex--;
216     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x07070707; /* R7. */
217     ulIndex--;
218     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x06060606; /* R6. */
219     ulIndex--;
220     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x05050505; /* R5. */
221     ulIndex--;
222     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x04040404; /* R4. */
223     ulIndex--;
224     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x03030303; /* R3. */
225     ulIndex--;
226     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x02020202; /* R2. */
227     ulIndex--;
228     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x01010101; /* R1. */
229     ulIndex--;
230     xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) pvParameters; /* R0. */
231     ulIndex--;
232 
233     #if( portENABLE_FPU == 1 )
234     {
235         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000015; /* S31. */
236         ulIndex--;
237         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1500000; /* S30. */
238         ulIndex--;
239         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000014; /* S29. */
240         ulIndex--;
241         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1400000; /* S28. */
242         ulIndex--;
243         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000013; /* S27. */
244         ulIndex--;
245         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1300000; /* S26. */
246         ulIndex--;
247         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000012; /* S25. */
248         ulIndex--;
249         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1200000; /* S24. */
250         ulIndex--;
251         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000011; /* S23. */
252         ulIndex--;
253         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1100000; /* S22. */
254         ulIndex--;
255         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000010; /* S21. */
256         ulIndex--;
257         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1000000; /* S20. */
258         ulIndex--;
259         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000009; /* S19. */
260         ulIndex--;
261         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD9000000; /* S18. */
262         ulIndex--;
263         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000008; /* S17. */
264         ulIndex--;
265         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD8000000; /* S16. */
266         ulIndex--;
267         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000007; /* S15. */
268         ulIndex--;
269         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD7000000; /* S14. */
270         ulIndex--;
271         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000006; /* S13. */
272         ulIndex--;
273         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD6000000; /* S12. */
274         ulIndex--;
275         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000005; /* S11. */
276         ulIndex--;
277         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD5000000; /* S10. */
278         ulIndex--;
279         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000004; /* S9. */
280         ulIndex--;
281         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD4000000; /* S8. */
282         ulIndex--;
283         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000003; /* S7. */
284         ulIndex--;
285         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD3000000; /* S6. */
286         ulIndex--;
287         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000002; /* S5. */
288         ulIndex--;
289         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD2000000; /* S4. */
290         ulIndex--;
291         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000001; /* S3. */
292         ulIndex--;
293         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1000000; /* S2. */
294         ulIndex--;
295         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000000; /* S1. */
296         ulIndex--;
297         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000000; /* S0. */
298         ulIndex--;
299 
300         xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x00000000; /* FPSR. */
301         ulIndex--;
302     }
303     #endif /* portENABLE_FPU */
304 
305     /* The task will start with a critical nesting count of 0. */
306     xMPUSettings->ulContext[ ulIndex ] = portNO_CRITICAL_NESTING;
307 
308     /* Ensure that the system call stack is double word aligned. */
309     xSysCallInfo = &( xMPUSettings->xSystemCallStackInfo );
310     xSysCallInfo->pulSystemCallStackPointer = &( xSysCallInfo->ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE - 1U ] );
311     xSysCallInfo->pulSystemCallStackPointer = ( uint32_t * ) ( ( ( uint32_t ) ( xSysCallInfo->pulSystemCallStackPointer ) ) &
312                                                                ( ( uint32_t ) ( ~( portBYTE_ALIGNMENT_MASK ) ) ) );
313 
314     /* This is not NULL only for the duration of a system call. */
315     xSysCallInfo->pulTaskStackPointer = NULL;
316 
317     /* Set the System Call to return to vPortSystemCallExit. */
318     xSysCallInfo->pulSystemCallExitAddress = ( uint32_t * ) ( &vPortSystemCallExit );
319 
320     /* Return the address where this task's context should be restored from. */
321     return &( xMPUSettings->ulContext[ ulIndex ] );
322 }
323 
324 /* ----------------------------------------------------------------------------------- */
325 
326 /**
327  * @brief Store a FreeRTOS task's MPU settings in its TCB.
328  *
329  * @ingroup Task Context
330  * @ingroup MPU Control
331  *
332  * @param xMPUSettings The MPU settings in TCB.
333  * @param xRegions The updated MPU settings requested by the task.
334  * @param pxBottomOfStack The base address of the task's Stack.
335  * @param ulStackDepth The length of the task's stack.
336  */
337 /* PRIVILEGED_FUNCTION */
vPortStoreTaskMPUSettings(xMPU_SETTINGS * xMPUSettings,const struct xMEMORY_REGION * const xRegions,StackType_t * pxBottomOfStack,uint32_t ulStackDepth)338 void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
339                                 const struct xMEMORY_REGION * const xRegions,
340                                 StackType_t * pxBottomOfStack,
341                                 uint32_t ulStackDepth )
342 {
343     #if defined( __ARMCC_VERSION )
344         /* Declaration when these variable are defined in code instead of being
345          * exported from linker scripts. */
346         extern uint32_t * __SRAM_segment_start__;
347         extern uint32_t * __SRAM_segment_end__;
348     #else
349         /* Declaration when these variable are exported from linker scripts. */
350         extern uint32_t __SRAM_segment_start__[];
351         extern uint32_t __SRAM_segment_end__[];
352     #endif /* if defined( __ARMCC_VERSION ) */
353 
354     uint32_t ulIndex = 0x0;
355     uint32_t ulRegionLength;
356     uint32_t ulRegionLengthEncoded;
357     uint32_t ulRegionLengthDecoded;
358 
359     if( xRegions == NULL )
360     {
361         /* No MPU regions are specified so allow access to all of the RAM. */
362         ulRegionLength = ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__;
363         ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength );
364         ulRegionLength |= portMPU_REGION_ENABLE;
365 
366         /* MPU Settings is zero'd out in the TCB before this function is called.
367          * We, therefore, do not need to explicitly zero out unused MPU regions
368          * in xMPUSettings. */
369         ulIndex = portSTACK_REGION;
370 
371         xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = ( uint32_t ) __SRAM_segment_start__;
372         xMPUSettings->xRegion[ ulIndex ].ulRegionSize = ( ulRegionLengthEncoded |
373                                                           portMPU_REGION_ENABLE );
374         xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = ( portMPU_REGION_PRIV_RW_USER_RW_NOEXEC |
375                                                                portMPU_REGION_NORMAL_OIWTNOWA_SHARED );
376     }
377     else
378     {
379         for( ulIndex = 0UL; ulIndex < portNUM_CONFIGURABLE_REGIONS; ulIndex++ )
380         {
381             /* If a length has been provided, the region is in use. */
382             if( ( xRegions[ ulIndex ] ).ulLengthInBytes > 0UL )
383             {
384                 ulRegionLength = xRegions[ ulIndex ].ulLengthInBytes;
385                 ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength );
386 
387                 /* MPU region base address must be aligned to the region size
388                  * boundary. */
389                 ulRegionLengthDecoded = 2UL << ( ulRegionLengthEncoded >> 1UL );
390                 configASSERT( ( ( ( uint32_t ) xRegions[ ulIndex ].pvBaseAddress ) % ( ulRegionLengthDecoded ) ) == 0UL );
391 
392                 xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = ( uint32_t ) xRegions[ ulIndex ].pvBaseAddress;
393                 xMPUSettings->xRegion[ ulIndex ].ulRegionSize = ( ulRegionLengthEncoded |
394                                                                   portMPU_REGION_ENABLE );
395                 xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = xRegions[ ulIndex ].ulParameters;
396             }
397             else
398             {
399                 xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = 0x0UL;
400                 xMPUSettings->xRegion[ ulIndex ].ulRegionSize = 0x0UL;
401                 xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = 0x0UL;
402             }
403         }
404 
405         /* This function is called automatically when the task is created - in
406          * which case the stack region parameters will be valid. At all other
407          * times the stack parameters will not be valid and it is assumed that the
408          * stack region has already been configured. */
409         if( ulStackDepth != 0x0UL )
410         {
411             ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) );
412 
413             /* MPU region base address must be aligned to the region size
414              * boundary. */
415             ulRegionLengthDecoded = 2UL << ( ulRegionLengthEncoded >> 1UL );
416             configASSERT( ( ( uint32_t ) pxBottomOfStack % ( ulRegionLengthDecoded ) ) == 0U );
417 
418             ulIndex = portSTACK_REGION;
419             xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = ( uint32_t ) pxBottomOfStack;
420             xMPUSettings->xRegion[ ulIndex ].ulRegionSize = ( ulRegionLengthEncoded |
421                                                               portMPU_REGION_ENABLE );;
422             xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = ( portMPU_REGION_PRIV_RW_USER_RW_NOEXEC |
423                                                                    portMPU_REGION_NORMAL_OIWTNOWA_SHARED );
424         }
425     }
426 }
427 
428 /* ----------------------------------------------------------------------------------- */
429 
430 /* PRIVILEGED_FUNCTION */
xPortIsTaskPrivileged(void)431 BaseType_t xPortIsTaskPrivileged( void )
432 {
433     BaseType_t xTaskIsPrivileged = pdFALSE;
434 
435     /* Calling task's MPU settings. */
436     const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL );
437 
438     if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
439     {
440         xTaskIsPrivileged = pdTRUE;
441     }
442 
443     return xTaskIsPrivileged;
444 }
445 
446 /* ----------------------------------------------------------------------------------- */
447 
448 /* PRIVILEGED_FUNCTION */
xPortStartScheduler(void)449 BaseType_t xPortStartScheduler( void )
450 {
451     /* Start the timer that generates the tick ISR. */
452     configSETUP_TICK_INTERRUPT();
453 
454     /* Configure MPU regions that are common to all tasks. */
455     prvSetupMPU();
456 
457     prvPortSchedulerRunning = pdTRUE;
458 
459     /* Load the context of the first task. */
460     vPortStartFirstTask();
461 
462     /* Will only get here if vTaskStartScheduler() was called with the CPU in
463      * a non-privileged mode or the binary point register was not set to its lowest
464      * possible value. prvTaskExitError() is referenced to prevent a compiler
465      * warning about it being defined but not referenced in the case that the user
466      * defines their own exit address. */
467     ( void ) prvTaskExitError();
468     return pdFALSE;
469 }
470 
471 /* ----------------------------------------------------------------------------------- */
472 
473 /* PRIVILEGED_FUNCTION */
prvGetMPURegionSizeEncoding(uint32_t ulActualMPURegionSize)474 static uint32_t prvGetMPURegionSizeEncoding( uint32_t ulActualMPURegionSize )
475 {
476     uint32_t ulRegionSize, ulReturnValue = 4U;
477 
478     /* 32 bytes is the smallest valid region for Cortex R4 and R5 CPUs. */
479     for( ulRegionSize = 0x20UL; ulReturnValue < 0x1FUL; ( ulRegionSize <<= 1UL ) )
480     {
481         if( ulActualMPURegionSize <= ulRegionSize )
482         {
483             break;
484         }
485         else
486         {
487             ulReturnValue++;
488         }
489     }
490 
491     /* Shift the code by one before returning so it can be written directly
492      * into the the correct bit position of the attribute register. */
493     return ulReturnValue << 1UL;
494 }
495 
496 /* ----------------------------------------------------------------------------------- */
497 
498 /* PRIVILEGED_FUNCTION */
prvSetupMPU(void)499 static void prvSetupMPU( void )
500 {
501 #if defined( __ARMCC_VERSION )
502     /* Declaration when these variable are defined in code. */
503     /* Sections used for FLASH. */
504     extern uint32_t * __FLASH_segment_start__;
505     extern uint32_t * __FLASH_segment_end__;
506     extern uint32_t * __privileged_functions_start__;
507     extern uint32_t * __privileged_functions_end__;
508 
509     /* Sections used for RAM. */
510     extern uint32_t * __SRAM_segment_start__;
511     extern uint32_t * __SRAM_segment_end__;
512     extern uint32_t * __privileged_data_start__;
513     extern uint32_t * __privileged_data_end__;
514 #else
515     /* Declaration when these variable are exported from linker scripts. */
516     /* Sections used for FLASH. */
517     extern uint32_t __FLASH_segment_start__[];
518     extern uint32_t __FLASH_segment_end__[];
519     extern uint32_t __privileged_functions_start__[];
520     extern uint32_t __privileged_functions_end__[];
521 
522     /* Sections used for RAM. */
523     extern uint32_t __SRAM_segment_start__[];
524     extern uint32_t __SRAM_segment_end__[];
525     extern uint32_t __privileged_data_start__[];
526     extern uint32_t __privileged_data_end__[];
527 #endif /* if defined( __ARMCC_VERSION ) */
528 
529     uint32_t ulRegionLength;
530     uint32_t ulRegionLengthEncoded;
531 
532     /* Disable the MPU before programming it. */
533     vMPUDisable();
534 
535     /* Priv: RX, Unpriv: RX for entire Flash. */
536     ulRegionLength = ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__;
537     ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength );
538     vMPUSetRegion( portUNPRIVILEGED_FLASH_REGION,
539                    ( uint32_t ) __FLASH_segment_start__,
540                    ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ),
541                    ( portMPU_REGION_PRIV_RO_USER_RO_EXEC |
542                      portMPU_REGION_NORMAL_OIWTNOWA_SHARED ) );
543 
544     /* Priv: RX, Unpriv: No access for privileged functions. */
545     ulRegionLength = ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__;
546     ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength );
547     vMPUSetRegion( portPRIVILEGED_FLASH_REGION,
548                    ( uint32_t ) __privileged_functions_start__,
549                    ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ),
550                    ( portMPU_REGION_PRIV_RO_USER_NA_EXEC |
551                      portMPU_REGION_NORMAL_OIWTNOWA_SHARED ) );
552 
553     /* Priv: RW, Unpriv: No Access for privileged data. */
554     ulRegionLength = ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__;
555     ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength );
556     vMPUSetRegion( portPRIVILEGED_RAM_REGION,
557                    ( uint32_t ) __privileged_data_start__,
558                    ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ),
559                    ( portMPU_REGION_PRIV_RW_USER_NA_NOEXEC |
560                      portMPU_REGION_PRIV_RW_USER_NA_NOEXEC ) );
561 
562     /* Enable the MPU background region - it allows privileged operating modes
563      * access to unmapped regions of memory without generating a fault. */
564     vMPUEnableBackgroundRegion();
565 
566     /* After setting default regions, enable the MPU. */
567     vMPUEnable();
568 }
569 
570 /* ----------------------------------------------------------------------------------- */
571 
572 /* PRIVILEGED_FUNCTION */
prvMPURegionAuthorizesBuffer(const xMPU_REGION_REGISTERS * xTaskMPURegion,const uint32_t ulBufferStart,const uint32_t ulBufferLength,const uint32_t ulAccessRequested)573 static BaseType_t prvMPURegionAuthorizesBuffer( const xMPU_REGION_REGISTERS * xTaskMPURegion,
574                                                 const uint32_t ulBufferStart,
575                                                 const uint32_t ulBufferLength,
576                                                 const uint32_t ulAccessRequested )
577 {
578     BaseType_t xAccessGranted = pdFALSE;
579     uint32_t ulBufferEnd;
580     uint32_t ulMPURegionLength;
581     uint32_t ulMPURegionStart;
582     uint32_t ulMPURegionEnd;
583     uint32_t ulMPURegionAccessPermissions;
584 
585     if( portADD_UINT32_WILL_OVERFLOW( ulBufferStart, ( ulBufferLength - 1UL ) ) == pdFALSE )
586     {
587         ulBufferEnd = ulBufferStart + ulBufferLength - 1UL;
588         ulMPURegionLength = 2UL << ( xTaskMPURegion->ulRegionSize >> 1UL );
589         ulMPURegionStart = xTaskMPURegion->ulRegionBaseAddress;
590         ulMPURegionEnd = xTaskMPURegion->ulRegionBaseAddress + ulMPURegionLength - 1UL;
591 
592         if( ( ulBufferStart >= ulMPURegionStart ) &&
593             ( ulBufferEnd <= ulMPURegionEnd ) &&
594             ( ulBufferStart <= ulBufferEnd ) )
595         {
596             ulMPURegionAccessPermissions = xTaskMPURegion->ulRegionAttribute & portMPU_REGION_AP_BITMASK;
597 
598             if( ulAccessRequested == tskMPU_READ_PERMISSION ) /* RO. */
599             {
600                 if( ( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RW_USER_RO ) ||
601                     ( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RO_USER_RO ) ||
602                     ( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RW_USER_RW ) )
603 
604                 {
605                     xAccessGranted = pdTRUE;
606                 }
607             }
608             else if( ( ulAccessRequested & tskMPU_WRITE_PERMISSION ) != 0UL ) /* W or RW. */
609             {
610                 if( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RW_USER_RW )
611                 {
612                     xAccessGranted = pdTRUE;
613                 }
614             }
615         }
616     }
617 
618     return xAccessGranted;
619 }
620 
621 /* ----------------------------------------------------------------------------------- */
622 
623 /* PRIVILEGED_FUNCTION */
xPortIsAuthorizedToAccessBuffer(const void * pvBuffer,uint32_t ulBufferLength,uint32_t ulAccessRequested)624 BaseType_t xPortIsAuthorizedToAccessBuffer( const void * pvBuffer,
625                                             uint32_t ulBufferLength,
626                                             uint32_t ulAccessRequested )
627 {
628     BaseType_t xAccessGranted = pdFALSE;
629     uint32_t ulRegionIndex;
630     xMPU_SETTINGS * xTaskMPUSettings = NULL;
631 
632     if( prvPortSchedulerRunning == pdFALSE )
633     {
634         /* Grant access to all the memory before the scheduler is started. It is
635          * necessary because there is no task running yet and therefore, we
636          * cannot use the permissions of any task. */
637         xAccessGranted = pdTRUE;
638     }
639     else
640     {
641         /* Calling task's MPU settings. */
642         xTaskMPUSettings = xTaskGetMPUSettings( NULL );
643 
644         if( ( xTaskMPUSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
645         {
646             /* Privileged tasks have access to all the memory. */
647             xAccessGranted = pdTRUE;
648         }
649         else
650         {
651             for( ulRegionIndex = 0x0UL; ulRegionIndex < portTOTAL_NUM_REGIONS_IN_TCB; ulRegionIndex++ )
652             {
653                 xAccessGranted = prvMPURegionAuthorizesBuffer( &( xTaskMPUSettings->xRegion[ ulRegionIndex ] ),
654                                                                ( uint32_t ) pvBuffer,
655                                                                ulBufferLength,
656                                                                ulAccessRequested );
657 
658                 if( xAccessGranted == pdTRUE )
659                 {
660                     break;
661                 }
662             }
663         }
664     }
665 
666     return xAccessGranted;
667 }
668 
669 /* ----------------------------------------------------------------------------------- */
670 
671 #if( configENABLE_ACCESS_CONTROL_LIST == 1 )
672 
673 /* PRIVILEGED_FUNCTION */
xPortIsAuthorizedToAccessKernelObject(int32_t lInternalIndexOfKernelObject)674 BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject )
675 {
676     uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
677     BaseType_t xAccessGranted = pdFALSE;
678     const xMPU_SETTINGS * xTaskMpuSettings;
679 
680     if( prvPortSchedulerRunning == pdFALSE )
681     {
682         /* Grant access to all the kernel objects before the scheduler
683          * is started. It is necessary because there is no task running
684          * yet and therefore, we cannot use the permissions of any
685          * task. */
686         xAccessGranted = pdTRUE;
687     }
688     else
689     {
690         /* Calling task's MPU settings. */
691         xTaskMpuSettings = xTaskGetMPUSettings( NULL );
692 
693         ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject
694                                           / portACL_ENTRY_SIZE_BITS );
695         ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject
696                                         % portACL_ENTRY_SIZE_BITS );
697 
698         if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
699         {
700             xAccessGranted = pdTRUE;
701         }
702         else
703         {
704             if( ( ( xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] ) &
705                   ( 1U << ulAccessControlListEntryBit ) ) != 0UL )
706             {
707                 xAccessGranted = pdTRUE;
708             }
709         }
710     }
711 
712     return xAccessGranted;
713 }
714 
715 #else
716 
717 /* PRIVILEGED_FUNCTION */
xPortIsAuthorizedToAccessKernelObject(int32_t lInternalIndexOfKernelObject)718 BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject )
719 {
720     ( void ) lInternalIndexOfKernelObject;
721 
722     /* If Access Control List feature is not used, all the tasks have
723      * access to all the kernel objects. */
724     return pdTRUE;
725 }
726 
727 #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
728 
729 /* ----------------------------------------------------------------------------------- */
730 
731 #if( configENABLE_ACCESS_CONTROL_LIST == 1 )
732 
733 /* PRIVILEGED_FUNCTION */
vPortGrantAccessToKernelObject(TaskHandle_t xInternalTaskHandle,int32_t lInternalIndexOfKernelObject)734 void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
735                                      int32_t lInternalIndexOfKernelObject )
736 {
737     uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
738     xMPU_SETTINGS * xTaskMpuSettings;
739 
740     ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject
741                                       / portACL_ENTRY_SIZE_BITS );
742     ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject
743                                     % portACL_ENTRY_SIZE_BITS );
744 
745     xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
746 
747     xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] |= ( 1U << ulAccessControlListEntryBit );
748 }
749 
750 #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
751 
752 /* ----------------------------------------------------------------------------------- */
753 
754 #if( configENABLE_ACCESS_CONTROL_LIST == 1 )
755 
756 /* PRIVILEGED_FUNCTION */
vPortRevokeAccessToKernelObject(TaskHandle_t xInternalTaskHandle,int32_t lInternalIndexOfKernelObject)757 void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
758                                       int32_t lInternalIndexOfKernelObject )
759 {
760     uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
761     xMPU_SETTINGS * xTaskMpuSettings;
762 
763     ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject
764                                       / portACL_ENTRY_SIZE_BITS );
765     ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject
766                                     % portACL_ENTRY_SIZE_BITS );
767 
768     xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
769 
770     xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] &= ~( 1U << ulAccessControlListEntryBit );
771 }
772 
773 #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */
774 
775 /* ----------------------------------------------------------------------------------- */
776 
prvTaskExitError(void)777 void prvTaskExitError( void )
778 {
779     /* A function that implements a task must not exit or attempt to return to
780      * its caller as there is nothing to return to. If a task wants to exit it
781      * should instead call vTaskDelete( NULL ).
782      *
783      * Artificially force an assert() to be triggered if configASSERT() is
784      * defined, then stop here so application writers can catch the error. */
785     configASSERT( ulPortInterruptNesting == ~0UL );
786 
787     for( ;; )
788     {
789     }
790 }
791 
792 /* ----------------------------------------------------------------------------------- */
793 
vPortEndScheduler(void)794 void vPortEndScheduler( void )
795 {
796     prvPortSchedulerRunning = pdFALSE;
797 
798     /* Not implemented in this port. Artificially force an assert. */
799     configASSERT( prvPortSchedulerRunning == pdTRUE );
800 }
801 
802 /* ----------------------------------------------------------------------------------- */
803 
804 /* PRIVILEGED_FUNCTION */
vPortEnterCritical(void)805 void vPortEnterCritical( void )
806 {
807     portDISABLE_INTERRUPTS();
808 
809     /* Now that interrupts are disabled, ulCriticalNesting can be accessed
810      * directly.  Increment ulCriticalNesting to keep a count of how many times
811      * portENTER_CRITICAL() has been called. */
812     ulCriticalNesting++;
813 
814     /* This is not the interrupt safe version of the enter critical function so
815      * assert() if it is being called from an interrupt context.  Only API
816      * functions that end in "FromISR" can be used in an interrupt.  Only assert
817      * if the critical nesting count is 1 to protect against recursive calls if
818      * the assert function also uses a critical section. */
819     if( ulCriticalNesting == 1 )
820     {
821         configASSERT( ulPortInterruptNesting == 0 );
822     }
823 }
824 /* ----------------------------------------------------------------------------------- */
825 
826 /* PRIVILEGED_FUNCTION */
vPortExitCritical(void)827 void vPortExitCritical( void )
828 {
829     if( ulCriticalNesting > portNO_CRITICAL_NESTING )
830     {
831         /* Decrement the nesting count as the critical section is being
832          * exited. */
833         ulCriticalNesting--;
834 
835         /* If the nesting level has reached zero then all interrupt
836          * priorities must be re-enabled. */
837         if( ulCriticalNesting == portNO_CRITICAL_NESTING )
838         {
839             /* Critical nesting has reached zero so all interrupt priorities
840              * should be unmasked. */
841             portENABLE_INTERRUPTS();
842         }
843     }
844 }
845 /* ----------------------------------------------------------------------------------- */
846