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