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