/* * FreeRTOS Kernel V11.1.0 * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS * */ /* Standard includes. */ #include /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining * all the API functions to use the MPU wrappers. That should only be done when * task.h is included from an application file. */ #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ /* Scheduler includes. */ #include "FreeRTOS.h" #include "portmacro.h" #include "task.h" #include "mpu_syscall_numbers.h" #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /* Max value that fits in a uint32_t type. */ #define portUINT32_MAX ( ~( ( uint32_t ) 0 ) ) /* Check if adding a and b will result in overflow. */ #define portADD_UINT32_WILL_OVERFLOW( a, b ) ( ( a ) > ( portUINT32_MAX - ( b ) ) ) /* ----------------------------------------------------------------------------------- */ /** * @brief Variable used to keep track of critical section nesting. * * @ingroup Critical Sections * * This variable is stored as part of the task context and must be initialised * to a non zero value to ensure interrupts don't inadvertently become unmasked * before the scheduler starts. As it is stored as part of the task context, it * will be set to 0 when the first task is started. */ PRIVILEGED_DATA volatile UBaseType_t ulCriticalNesting = 0xFFFF; /** * @brief Set to 1 to pend a context switch from an ISR. * * @ingroup Interrupt Management */ PRIVILEGED_DATA volatile UBaseType_t ulPortYieldRequired = pdFALSE; /** * @brief Interrupt nesting depth, used to count the number of interrupts to unwind. * * @ingroup Interrupt Management */ PRIVILEGED_DATA volatile UBaseType_t ulPortInterruptNesting = 0UL; /** * @brief Variable to track whether or not the scheduler has been started. * * @ingroup Scheduler * * This is the port specific version of the xSchedulerRunning in tasks.c. */ PRIVILEGED_DATA static BaseType_t prvPortSchedulerRunning = pdFALSE; /* -------------------------- Private Function Declarations -------------------------- */ /** * @brief Determine if the given MPU region settings authorizes the requested * access to the given buffer. * * @ingroup Task Context * @ingroup MPU Control * * @param xTaskMPURegion MPU region settings. * @param ulBufferStart Start address of the given buffer. * @param ulBufferLength Length of the given buffer. * @param ulAccessRequested Access requested. * * @return pdTRUE if MPU region settins authorizes the requested access to the * given buffer, pdFALSE otherwise. */ PRIVILEGED_FUNCTION static BaseType_t prvMPURegionAuthorizesBuffer( const xMPU_REGION_REGISTERS * xTaskMPURegion, const uint32_t ulBufferStart, const uint32_t ulBufferLength, const uint32_t ulAccessRequested ); /** * @brief Determine the smallest MPU Region Size Encoding for the given MPU * region size. * * @ingroup MPU Control * * @param ulActualMPURegionSize MPU region size in bytes. * * @return The smallest MPU Region Size Encoding for the given MPU region size. */ PRIVILEGED_FUNCTION static uint32_t prvGetMPURegionSizeEncoding( uint32_t ulActualMPURegionSize ); /** * @brief Set up MPU. * * @ingroup MPU Control */ PRIVILEGED_FUNCTION static void prvSetupMPU( void ); /* -------------------------- Exported Function Declarations -------------------------- */ /** * @brief Enter critical section. * * @ingroup Critical Section */ PRIVILEGED_FUNCTION void vPortEnterCritical( void ); /** * @brief Exit critical section. * * @ingroup Critical Section */ PRIVILEGED_FUNCTION void vPortExitCritical( void ); /* ----------------------------------------------------------------------------------- */ /** * @brief Setup a FreeRTOS task's initial context. * * @ingroup Task Context * * @param pxTopOfStack Top of stack. * @param pxCode The task function. * @param pvParameters Argument passed to the task function. * @param xRunPrivileged Marks if the task is privileged. * @param xMPUSettings MPU settings of the task. * * @return Location where to restore the task's context from. */ /* PRIVILEGED_FUNCTION */ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, TaskFunction_t pxCode, void * pvParameters, BaseType_t xRunPrivileged, xMPU_SETTINGS * xMPUSettings ) { /* Setup the initial context of the task. The context is set exactly as * expected by the portRESTORE_CONTEXT() macro. */ UBaseType_t ulIndex = CONTEXT_SIZE - 1U; xSYSTEM_CALL_STACK_INFO * xSysCallInfo = NULL; if( xRunPrivileged == pdTRUE ) { xMPUSettings->ulTaskFlags |= portTASK_IS_PRIVILEGED_FLAG; /* Current Program Status Register (CPSR). */ xMPUSettings->ulContext[ ulIndex ] = SYS_MODE; } else { xMPUSettings->ulTaskFlags &= ( ~portTASK_IS_PRIVILEGED_FLAG ); /* Current Program Status Register (CPSR). */ xMPUSettings->ulContext[ ulIndex ] = USER_MODE; } if( ( ( uint32_t ) pxCode & portTHUMB_MODE_ADDRESS ) != 0x0UL ) { /* The task will cause the processor to start in THUMB state, set the * Thumb state bit in the CPSR. */ xMPUSettings->ulContext[ ulIndex ] |= portTHUMB_MODE_BIT; } ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) pxCode; /* PC. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) pxTopOfStack; /* SP. */ ulIndex--; /* General Purpose Registers. */ xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x12121212; /* R12. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x11111111; /* R11. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x10101010; /* R10. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x09090909; /* R9. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x08080808; /* R8. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x07070707; /* R7. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x06060606; /* R6. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x05050505; /* R5. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x04040404; /* R4. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x03030303; /* R3. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x02020202; /* R2. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x01010101; /* R1. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) pvParameters; /* R0. */ ulIndex--; #if( portENABLE_FPU == 1 ) { xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000015; /* S31. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1500000; /* S30. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000014; /* S29. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1400000; /* S28. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000013; /* S27. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1300000; /* S26. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000012; /* S25. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1200000; /* S24. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000011; /* S23. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1100000; /* S22. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000010; /* S21. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1000000; /* S20. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000009; /* S19. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD9000000; /* S18. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000008; /* S17. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD8000000; /* S16. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000007; /* S15. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD7000000; /* S14. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000006; /* S13. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD6000000; /* S12. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000005; /* S11. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD5000000; /* S10. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000004; /* S9. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD4000000; /* S8. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000003; /* S7. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD3000000; /* S6. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000002; /* S5. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD2000000; /* S4. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000001; /* S3. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD1000000; /* S2. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000000; /* S1. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0xD0000000; /* S0. */ ulIndex--; xMPUSettings->ulContext[ ulIndex ] = ( StackType_t ) 0x00000000; /* FPSR. */ ulIndex--; } #endif /* portENABLE_FPU */ /* The task will start with a critical nesting count of 0. */ xMPUSettings->ulContext[ ulIndex ] = portNO_CRITICAL_NESTING; /* Ensure that the system call stack is double word aligned. */ xSysCallInfo = &( xMPUSettings->xSystemCallStackInfo ); xSysCallInfo->pulSystemCallStackPointer = &( xSysCallInfo->ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE - 1U ] ); xSysCallInfo->pulSystemCallStackPointer = ( uint32_t * ) ( ( ( uint32_t ) ( xSysCallInfo->pulSystemCallStackPointer ) ) & ( ( uint32_t ) ( ~( portBYTE_ALIGNMENT_MASK ) ) ) ); /* This is not NULL only for the duration of a system call. */ xSysCallInfo->pulTaskStackPointer = NULL; /* Set the System Call to return to vPortSystemCallExit. */ xSysCallInfo->pulSystemCallExitAddress = ( uint32_t * ) ( &vPortSystemCallExit ); /* Return the address where this task's context should be restored from. */ return &( xMPUSettings->ulContext[ ulIndex ] ); } /* ----------------------------------------------------------------------------------- */ /** * @brief Store a FreeRTOS task's MPU settings in its TCB. * * @ingroup Task Context * @ingroup MPU Control * * @param xMPUSettings The MPU settings in TCB. * @param xRegions The updated MPU settings requested by the task. * @param pxBottomOfStack The base address of the task's Stack. * @param ulStackDepth The length of the task's stack. */ /* PRIVILEGED_FUNCTION */ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t * pxBottomOfStack, uint32_t ulStackDepth ) { #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __SRAM_segment_start__; extern uint32_t * __SRAM_segment_end__; #else /* Declaration when these variable are exported from linker scripts. */ extern uint32_t __SRAM_segment_start__[]; extern uint32_t __SRAM_segment_end__[]; #endif /* if defined( __ARMCC_VERSION ) */ uint32_t ulIndex = 0x0; uint32_t ulRegionLength; uint32_t ulRegionLengthEncoded; uint32_t ulRegionLengthDecoded; if( xRegions == NULL ) { /* No MPU regions are specified so allow access to all of the RAM. */ ulRegionLength = ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__; ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength ); ulRegionLength |= portMPU_REGION_ENABLE; /* MPU Settings is zero'd out in the TCB before this function is called. * We, therefore, do not need to explicitly zero out unused MPU regions * in xMPUSettings. */ ulIndex = portSTACK_REGION; xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = ( uint32_t ) __SRAM_segment_start__; xMPUSettings->xRegion[ ulIndex ].ulRegionSize = ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ); xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = ( portMPU_REGION_PRIV_RW_USER_RW_NOEXEC | portMPU_REGION_NORMAL_OIWTNOWA_SHARED ); } else { for( ulIndex = 0UL; ulIndex < portNUM_CONFIGURABLE_REGIONS; ulIndex++ ) { /* If a length has been provided, the region is in use. */ if( ( xRegions[ ulIndex ] ).ulLengthInBytes > 0UL ) { ulRegionLength = xRegions[ ulIndex ].ulLengthInBytes; ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength ); /* MPU region base address must be aligned to the region size * boundary. */ ulRegionLengthDecoded = 2UL << ( ulRegionLengthEncoded >> 1UL ); configASSERT( ( ( ( uint32_t ) xRegions[ ulIndex ].pvBaseAddress ) % ( ulRegionLengthDecoded ) ) == 0UL ); xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = ( uint32_t ) xRegions[ ulIndex ].pvBaseAddress; xMPUSettings->xRegion[ ulIndex ].ulRegionSize = ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ); xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = xRegions[ ulIndex ].ulParameters; } else { xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = 0x0UL; xMPUSettings->xRegion[ ulIndex ].ulRegionSize = 0x0UL; xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = 0x0UL; } } /* This function is called automatically when the task is created - in * which case the stack region parameters will be valid. At all other * times the stack parameters will not be valid and it is assumed that the * stack region has already been configured. */ if( ulStackDepth != 0x0UL ) { ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ); /* MPU region base address must be aligned to the region size * boundary. */ ulRegionLengthDecoded = 2UL << ( ulRegionLengthEncoded >> 1UL ); configASSERT( ( ( uint32_t ) pxBottomOfStack % ( ulRegionLengthDecoded ) ) == 0U ); ulIndex = portSTACK_REGION; xMPUSettings->xRegion[ ulIndex ].ulRegionBaseAddress = ( uint32_t ) pxBottomOfStack; xMPUSettings->xRegion[ ulIndex ].ulRegionSize = ( ulRegionLengthEncoded | portMPU_REGION_ENABLE );; xMPUSettings->xRegion[ ulIndex ].ulRegionAttribute = ( portMPU_REGION_PRIV_RW_USER_RW_NOEXEC | portMPU_REGION_NORMAL_OIWTNOWA_SHARED ); } } } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ BaseType_t xPortIsTaskPrivileged( void ) { BaseType_t xTaskIsPrivileged = pdFALSE; /* Calling task's MPU settings. */ const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL ); if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG ) { xTaskIsPrivileged = pdTRUE; } return xTaskIsPrivileged; } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ BaseType_t xPortStartScheduler( void ) { /* Start the timer that generates the tick ISR. */ configSETUP_TICK_INTERRUPT(); /* Configure MPU regions that are common to all tasks. */ prvSetupMPU(); prvPortSchedulerRunning = pdTRUE; /* Load the context of the first task. */ vPortStartFirstTask(); /* Will only get here if vTaskStartScheduler() was called with the CPU in * a non-privileged mode or the binary point register was not set to its lowest * possible value. prvTaskExitError() is referenced to prevent a compiler * warning about it being defined but not referenced in the case that the user * defines their own exit address. */ ( void ) prvTaskExitError(); return pdFALSE; } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ static uint32_t prvGetMPURegionSizeEncoding( uint32_t ulActualMPURegionSize ) { uint32_t ulRegionSize, ulReturnValue = 4U; /* 32 bytes is the smallest valid region for Cortex R4 and R5 CPUs. */ for( ulRegionSize = 0x20UL; ulReturnValue < 0x1FUL; ( ulRegionSize <<= 1UL ) ) { if( ulActualMPURegionSize <= ulRegionSize ) { break; } else { ulReturnValue++; } } /* Shift the code by one before returning so it can be written directly * into the the correct bit position of the attribute register. */ return ulReturnValue << 1UL; } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ static void prvSetupMPU( void ) { #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code. */ /* Sections used for FLASH. */ extern uint32_t * __FLASH_segment_start__; extern uint32_t * __FLASH_segment_end__; extern uint32_t * __privileged_functions_start__; extern uint32_t * __privileged_functions_end__; /* Sections used for RAM. */ extern uint32_t * __SRAM_segment_start__; extern uint32_t * __SRAM_segment_end__; extern uint32_t * __privileged_data_start__; extern uint32_t * __privileged_data_end__; #else /* Declaration when these variable are exported from linker scripts. */ /* Sections used for FLASH. */ extern uint32_t __FLASH_segment_start__[]; extern uint32_t __FLASH_segment_end__[]; extern uint32_t __privileged_functions_start__[]; extern uint32_t __privileged_functions_end__[]; /* Sections used for RAM. */ extern uint32_t __SRAM_segment_start__[]; extern uint32_t __SRAM_segment_end__[]; extern uint32_t __privileged_data_start__[]; extern uint32_t __privileged_data_end__[]; #endif /* if defined( __ARMCC_VERSION ) */ uint32_t ulRegionLength; uint32_t ulRegionLengthEncoded; /* Disable the MPU before programming it. */ vMPUDisable(); /* Priv: RX, Unpriv: RX for entire Flash. */ ulRegionLength = ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__; ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength ); vMPUSetRegion( portUNPRIVILEGED_FLASH_REGION, ( uint32_t ) __FLASH_segment_start__, ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ), ( portMPU_REGION_PRIV_RO_USER_RO_EXEC | portMPU_REGION_NORMAL_OIWTNOWA_SHARED ) ); /* Priv: RX, Unpriv: No access for privileged functions. */ ulRegionLength = ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__; ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength ); vMPUSetRegion( portPRIVILEGED_FLASH_REGION, ( uint32_t ) __privileged_functions_start__, ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ), ( portMPU_REGION_PRIV_RO_USER_NA_EXEC | portMPU_REGION_NORMAL_OIWTNOWA_SHARED ) ); /* Priv: RW, Unpriv: No Access for privileged data. */ ulRegionLength = ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__; ulRegionLengthEncoded = prvGetMPURegionSizeEncoding( ulRegionLength ); vMPUSetRegion( portPRIVILEGED_RAM_REGION, ( uint32_t ) __privileged_data_start__, ( ulRegionLengthEncoded | portMPU_REGION_ENABLE ), ( portMPU_REGION_PRIV_RW_USER_NA_NOEXEC | portMPU_REGION_PRIV_RW_USER_NA_NOEXEC ) ); /* Enable the MPU background region - it allows privileged operating modes * access to unmapped regions of memory without generating a fault. */ vMPUEnableBackgroundRegion(); /* After setting default regions, enable the MPU. */ vMPUEnable(); } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ static BaseType_t prvMPURegionAuthorizesBuffer( const xMPU_REGION_REGISTERS * xTaskMPURegion, const uint32_t ulBufferStart, const uint32_t ulBufferLength, const uint32_t ulAccessRequested ) { BaseType_t xAccessGranted = pdFALSE; uint32_t ulBufferEnd; uint32_t ulMPURegionLength; uint32_t ulMPURegionStart; uint32_t ulMPURegionEnd; uint32_t ulMPURegionAccessPermissions; if( portADD_UINT32_WILL_OVERFLOW( ulBufferStart, ( ulBufferLength - 1UL ) ) == pdFALSE ) { ulBufferEnd = ulBufferStart + ulBufferLength - 1UL; ulMPURegionLength = 2UL << ( xTaskMPURegion->ulRegionSize >> 1UL ); ulMPURegionStart = xTaskMPURegion->ulRegionBaseAddress; ulMPURegionEnd = xTaskMPURegion->ulRegionBaseAddress + ulMPURegionLength - 1UL; if( ( ulBufferStart >= ulMPURegionStart ) && ( ulBufferEnd <= ulMPURegionEnd ) && ( ulBufferStart <= ulBufferEnd ) ) { ulMPURegionAccessPermissions = xTaskMPURegion->ulRegionAttribute & portMPU_REGION_AP_BITMASK; if( ulAccessRequested == tskMPU_READ_PERMISSION ) /* RO. */ { if( ( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RW_USER_RO ) || ( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RO_USER_RO ) || ( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RW_USER_RW ) ) { xAccessGranted = pdTRUE; } } else if( ( ulAccessRequested & tskMPU_WRITE_PERMISSION ) != 0UL ) /* W or RW. */ { if( ulMPURegionAccessPermissions == portMPU_REGION_PRIV_RW_USER_RW ) { xAccessGranted = pdTRUE; } } } } return xAccessGranted; } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ BaseType_t xPortIsAuthorizedToAccessBuffer( const void * pvBuffer, uint32_t ulBufferLength, uint32_t ulAccessRequested ) { BaseType_t xAccessGranted = pdFALSE; uint32_t ulRegionIndex; xMPU_SETTINGS * xTaskMPUSettings = NULL; if( prvPortSchedulerRunning == pdFALSE ) { /* Grant access to all the memory before the scheduler is started. It is * necessary because there is no task running yet and therefore, we * cannot use the permissions of any task. */ xAccessGranted = pdTRUE; } else { /* Calling task's MPU settings. */ xTaskMPUSettings = xTaskGetMPUSettings( NULL ); if( ( xTaskMPUSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG ) { /* Privileged tasks have access to all the memory. */ xAccessGranted = pdTRUE; } else { for( ulRegionIndex = 0x0UL; ulRegionIndex < portTOTAL_NUM_REGIONS_IN_TCB; ulRegionIndex++ ) { xAccessGranted = prvMPURegionAuthorizesBuffer( &( xTaskMPUSettings->xRegion[ ulRegionIndex ] ), ( uint32_t ) pvBuffer, ulBufferLength, ulAccessRequested ); if( xAccessGranted == pdTRUE ) { break; } } } } return xAccessGranted; } /* ----------------------------------------------------------------------------------- */ #if( configENABLE_ACCESS_CONTROL_LIST == 1 ) /* PRIVILEGED_FUNCTION */ BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) { uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit; BaseType_t xAccessGranted = pdFALSE; const xMPU_SETTINGS * xTaskMpuSettings; if( prvPortSchedulerRunning == pdFALSE ) { /* Grant access to all the kernel objects before the scheduler * is started. It is necessary because there is no task running * yet and therefore, we cannot use the permissions of any * task. */ xAccessGranted = pdTRUE; } else { /* Calling task's MPU settings. */ xTaskMpuSettings = xTaskGetMPUSettings( NULL ); ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS ); ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS ); if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG ) { xAccessGranted = pdTRUE; } else { if( ( ( xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] ) & ( 1U << ulAccessControlListEntryBit ) ) != 0UL ) { xAccessGranted = pdTRUE; } } } return xAccessGranted; } #else /* PRIVILEGED_FUNCTION */ BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) { ( void ) lInternalIndexOfKernelObject; /* If Access Control List feature is not used, all the tasks have * access to all the kernel objects. */ return pdTRUE; } #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */ /* ----------------------------------------------------------------------------------- */ #if( configENABLE_ACCESS_CONTROL_LIST == 1 ) /* PRIVILEGED_FUNCTION */ void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, int32_t lInternalIndexOfKernelObject ) { uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit; xMPU_SETTINGS * xTaskMpuSettings; ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS ); ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS ); xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle ); xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] |= ( 1U << ulAccessControlListEntryBit ); } #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */ /* ----------------------------------------------------------------------------------- */ #if( configENABLE_ACCESS_CONTROL_LIST == 1 ) /* PRIVILEGED_FUNCTION */ void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle, int32_t lInternalIndexOfKernelObject ) { uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit; xMPU_SETTINGS * xTaskMpuSettings; ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS ); ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS ); xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle ); xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] &= ~( 1U << ulAccessControlListEntryBit ); } #endif /* #if ( configENABLE_ACCESS_CONTROL_LIST == 1 ) */ /* ----------------------------------------------------------------------------------- */ void prvTaskExitError( void ) { /* A function that implements a task must not exit or attempt to return to * its caller as there is nothing to return to. If a task wants to exit it * should instead call vTaskDelete( NULL ). * * Artificially force an assert() to be triggered if configASSERT() is * defined, then stop here so application writers can catch the error. */ configASSERT( ulPortInterruptNesting == ~0UL ); for( ;; ) { } } /* ----------------------------------------------------------------------------------- */ void vPortEndScheduler( void ) { prvPortSchedulerRunning = pdFALSE; /* Not implemented in this port. Artificially force an assert. */ configASSERT( prvPortSchedulerRunning == pdTRUE ); } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); /* Now that interrupts are disabled, ulCriticalNesting can be accessed * directly. Increment ulCriticalNesting to keep a count of how many times * portENTER_CRITICAL() has been called. */ ulCriticalNesting++; /* This is not the interrupt safe version of the enter critical function so * assert() if it is being called from an interrupt context. Only API * functions that end in "FromISR" can be used in an interrupt. Only assert * if the critical nesting count is 1 to protect against recursive calls if * the assert function also uses a critical section. */ if( ulCriticalNesting == 1 ) { configASSERT( ulPortInterruptNesting == 0 ); } } /* ----------------------------------------------------------------------------------- */ /* PRIVILEGED_FUNCTION */ void vPortExitCritical( void ) { if( ulCriticalNesting > portNO_CRITICAL_NESTING ) { /* Decrement the nesting count as the critical section is being * exited. */ ulCriticalNesting--; /* If the nesting level has reached zero then all interrupt * priorities must be re-enabled. */ if( ulCriticalNesting == portNO_CRITICAL_NESTING ) { /* Critical nesting has reached zero so all interrupt priorities * should be unmasked. */ portENABLE_INTERRUPTS(); } } } /* ----------------------------------------------------------------------------------- */