Memory Protection Unit (MPU) Enhancements (#705)

Memory Protection Unit (MPU) Enhancements

This commit introduces a new MPU wrapper that places additional
restrictions on unprivileged tasks. The following is the list of changes
introduced with the new MPU wrapper:

1. Opaque and indirectly verifiable integers for kernel object handles:
   All the kernel object handles (for example, queue handles) are now
   opaque integers. Previously object handles were raw pointers.

2. Saving the task context in Task Control Block (TCB): When a task is
   swapped out by the scheduler, the task's context is now saved in its
   TCB. Previously the task's context was saved on its stack.

3. Execute system calls on a separate privileged only stack: FreeRTOS
   system calls, which execute with elevated privilege, now use a
   separate privileged only stack. Previously system calls used the
   calling task's stack. The application writer can control the size of
   the system call stack using new configSYSTEM_CALL_STACK_SIZE config
   macro.

4. Memory bounds checks: FreeRTOS system calls which accept a pointer
   and de-reference it, now verify that the calling task has required
   permissions to access the memory location referenced by the pointer.

5. System call restrictions: The following system calls are no longer
   available to unprivileged tasks:
    - vQueueDelete
    - xQueueCreateMutex
    - xQueueCreateMutexStatic
    - xQueueCreateCountingSemaphore
    - xQueueCreateCountingSemaphoreStatic
    - xQueueGenericCreate
    - xQueueGenericCreateStatic
    - xQueueCreateSet
    - xQueueRemoveFromSet
    - xQueueGenericReset
    - xTaskCreate
    - xTaskCreateStatic
    - vTaskDelete
    - vTaskPrioritySet
    - vTaskSuspendAll
    - xTaskResumeAll
    - xTaskGetHandle
    - xTaskCallApplicationTaskHook
    - vTaskList
    - vTaskGetRunTimeStats
    - xTaskCatchUpTicks
    - xEventGroupCreate
    - xEventGroupCreateStatic
    - vEventGroupDelete
    - xStreamBufferGenericCreate
    - xStreamBufferGenericCreateStatic
    - vStreamBufferDelete
    - xStreamBufferReset
   Also, an unprivileged task can no longer use vTaskSuspend to suspend
   any task other than itself.

We thank the following people for their inputs in these enhancements:
- David Reiss of Meta Platforms, Inc.
- Lan Luo, Xinhui Shao, Yumeng Wei, Zixia Liu, Huaiyu Yan and Zhen Ling
  of School of Computer Science and Engineering, Southeast University,
  China.
- Xinwen Fu of Department of Computer Science, University of
  Massachusetts Lowell, USA.
- Yuequi Chen, Zicheng Wang, Minghao Lin of University of Colorado
  Boulder, USA.
This commit is contained in:
kar-rahul-aws 2023-07-13 16:51:04 +05:30 committed by GitHub
parent 18e2937239
commit 97050a17aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
123 changed files with 94802 additions and 6515 deletions

View file

@ -132,8 +132,14 @@
#define portINITIAL_CONTROL_IF_UNPRIVILEGED ( 0x03 )
#define portINITIAL_CONTROL_IF_PRIVILEGED ( 0x02 )
/* Constants used during system call enter and exit. */
#define portPSR_STACK_PADDING_MASK ( 1UL << 9UL )
#define portEXC_RETURN_STACK_FRAME_TYPE_MASK ( 1UL << 4UL )
/* Offsets in the stack to the parameters when inside the SVC handler. */
#define portOFFSET_TO_LR ( 5 )
#define portOFFSET_TO_PC ( 6 )
#define portOFFSET_TO_PSR ( 7 )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
@ -147,6 +153,21 @@
* have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* Does addr lie within [start, end] address range? */
#define portIS_ADDRESS_WITHIN_RANGE( addr, start, end ) \
( ( ( addr ) >= ( start ) ) && ( ( addr ) <= ( end ) ) )
/* Is the access request satisfied by the available permissions? */
#define portIS_AUTHORIZED( accessRequest, permissions ) \
( ( ( permissions ) & ( accessRequest ) ) == accessRequest )
/* 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 ) ) )
/*-----------------------------------------------------------*/
/*
* Configure a number of standard MPU regions that are used by all tasks.
*/
@ -184,7 +205,7 @@ extern void vPortEnableVFP( void );
/*
* The C portion of the SVC handler.
*/
void vPortSVCHandler_C( uint32_t * pulParam );
void vPortSVCHandler_C( uint32_t * pulParam ) PRIVILEGED_FUNCTION;
/*
* Called from the SVC handler used to start the scheduler.
@ -208,6 +229,57 @@ extern void vPortRestoreContextOfFirstTask( void ) PRIVILEGED_FUNCTION;
#else
void vPortExitCritical( void ) PRIVILEGED_FUNCTION;
#endif
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
/**
* @brief Sets up the system call stack so that upon returning from
* SVC, the system call stack is used.
*
* It is used for the system calls with up to 4 parameters.
*
* @param pulTaskStack The current SP when the SVC was raised.
* @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler.
*/
void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR ) PRIVILEGED_FUNCTION;
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
/**
* @brief Sets up the system call stack so that upon returning from
* SVC, the system call stack is used.
*
* It is used for the system calls with 5 parameters.
*
* @param pulTaskStack The current SP when the SVC was raised.
* @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler.
*/
void vSystemCallEnter_1( uint32_t * pulTaskStack, uint32_t ulLR ) PRIVILEGED_FUNCTION;
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
/**
* @brief Sets up the task stack so that upon returning from
* SVC, the task stack is used again.
*
* @param pulSystemCallStack The current SP when the SVC was raised.
* @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler.
*/
void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION;
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/**
* @brief Checks whether or not the calling task is privileged.
*
* @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
*/
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
@ -233,46 +305,56 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged )
BaseType_t xRunPrivileged,
xMPU_SETTINGS * xMPUSettings )
{
/* Simulate the stack frame as it would be created by a context switch
* interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
* of interrupts, and to ensure alignment. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0; /* LR */
/* Save code space by skipping register initialisation. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its
* own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN;
pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
if( xRunPrivileged == pdTRUE )
{
*pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;
xMPUSettings->ulTaskFlags |= portTASK_IS_PRIVILEGED_FLAG;
xMPUSettings->ulContext[ 0 ] = portINITIAL_CONTROL_IF_PRIVILEGED;
}
else
{
*pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;
xMPUSettings->ulTaskFlags &= ( ~portTASK_IS_PRIVILEGED_FLAG );
xMPUSettings->ulContext[ 0 ] = portINITIAL_CONTROL_IF_UNPRIVILEGED;
}
xMPUSettings->ulContext[ 1 ] = 0x04040404; /* r4. */
xMPUSettings->ulContext[ 2 ] = 0x05050505; /* r5. */
xMPUSettings->ulContext[ 3 ] = 0x06060606; /* r6. */
xMPUSettings->ulContext[ 4 ] = 0x07070707; /* r7. */
xMPUSettings->ulContext[ 5 ] = 0x08080808; /* r8. */
xMPUSettings->ulContext[ 6 ] = 0x09090909; /* r9. */
xMPUSettings->ulContext[ 7 ] = 0x10101010; /* r10. */
xMPUSettings->ulContext[ 8 ] = 0x11111111; /* r11. */
xMPUSettings->ulContext[ 9 ] = portINITIAL_EXC_RETURN; /* EXC_RETURN. */
return pxTopOfStack;
xMPUSettings->ulContext[ 10 ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */
xMPUSettings->ulContext[ 11 ] = ( uint32_t ) pvParameters; /* r0. */
xMPUSettings->ulContext[ 12 ] = 0x01010101; /* r1. */
xMPUSettings->ulContext[ 13 ] = 0x02020202; /* r2. */
xMPUSettings->ulContext[ 14 ] = 0x03030303; /* r3. */
xMPUSettings->ulContext[ 15 ] = 0x12121212; /* r12. */
xMPUSettings->ulContext[ 16 ] = 0; /* LR. */
xMPUSettings->ulContext[ 17 ] = ( ( uint32_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC. */
xMPUSettings->ulContext[ 18 ] = portINITIAL_XPSR; /* xPSR. */
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
{
/* Ensure that the system call stack is double word aligned. */
xMPUSettings->xSystemCallStackInfo.pulSystemCallStack = &( xMPUSettings->xSystemCallStackInfo.ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE - 1 ] );
xMPUSettings->xSystemCallStackInfo.pulSystemCallStack = ( uint32_t * ) ( ( uint32_t ) ( xMPUSettings->xSystemCallStackInfo.pulSystemCallStack ) &
( uint32_t ) ( ~( portBYTE_ALIGNMENT_MASK ) ) );
/* This is not NULL only for the duration of a system call. */
xMPUSettings->xSystemCallStackInfo.pulTaskStack = NULL;
}
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
return &( xMPUSettings->ulContext[ 19 ] );
}
/*-----------------------------------------------------------*/
void vPortSVCHandler_C( uint32_t * pulParam )
void vPortSVCHandler_C( uint32_t * pulParam ) /* PRIVILEGED_FUNCTION */
{
uint8_t ucSVCNumber;
uint32_t ulPC;
@ -334,7 +416,7 @@ void vPortSVCHandler_C( uint32_t * pulParam )
::: "r1", "memory"
);
break;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
default: /* Unknown SVC call. */
break;
@ -342,6 +424,308 @@ void vPortSVCHandler_C( uint32_t * pulParam )
}
/*-----------------------------------------------------------*/
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR ) /* PRIVILEGED_FUNCTION */
{
extern TaskHandle_t pxCurrentTCB;
xMPU_SETTINGS * pxMpuSettings;
uint32_t * pulSystemCallStack;
uint32_t ulStackFrameSize, ulSystemCallLocation, i;
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__;
extern uint32_t * __syscalls_flash_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* #if defined( __ARMCC_VERSION ) */
ulSystemCallLocation = pulTaskStack[ portOFFSET_TO_PC ];
/* If the request did not come from the system call section, do nothing. */
if( ( ulSystemCallLocation >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulSystemCallLocation <= ( uint32_t ) __syscalls_flash_end__ ) )
{
pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack;
/* This is not NULL only for the duration of the system call. */
configASSERT( pxMpuSettings->xSystemCallStackInfo.pulTaskStack == NULL );
if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL )
{
/* Extended frame i.e. FPU in use. */
ulStackFrameSize = 26;
__asm volatile (
" vpush {s0} \n" /* Trigger lazy stacking. */
" vpop {s0} \n" /* Nullify the affect of the above instruction. */
::: "memory"
);
}
else
{
/* Standard frame i.e. FPU not in use. */
ulStackFrameSize = 8;
}
/* Make space on the system call stack for the stack frame. */
pulSystemCallStack = pulSystemCallStack - ulStackFrameSize;
/* Copy the stack frame. */
for( i = 0; i < ulStackFrameSize; i++ )
{
pulSystemCallStack[ i ] = pulTaskStack[ i ];
}
/* Use the pulSystemCallStack in thread mode. */
__asm volatile ( "msr psp, %0" : : "r" ( pulSystemCallStack ) );
/* Raise the privilege for the duration of the system call. */
__asm volatile (
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Clear nPRIV bit. */
" msr control, r1 \n" /* Write back new control value. */
::: "r1", "memory"
);
/* Remember the location where we should copy the stack frame when we exit from
* the system call. */
pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize;
/* Store the value of the Link Register before the SVC was raised. We need to
* restore it when we exit from the system call. */
pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry = pulTaskStack[ portOFFSET_TO_LR ];
/* Record if the hardware used padding to force the stack pointer
* to be double word aligned. */
if( ( pulTaskStack[ portOFFSET_TO_PSR ] & portPSR_STACK_PADDING_MASK ) == portPSR_STACK_PADDING_MASK )
{
pxMpuSettings->ulTaskFlags |= portSTACK_FRAME_HAS_PADDING_FLAG;
}
else
{
pxMpuSettings->ulTaskFlags &= ( ~portSTACK_FRAME_HAS_PADDING_FLAG );
}
/* We ensure in pxPortInitialiseStack that the system call stack is
* double word aligned and therefore, there is no need of padding.
* Clear the bit[9] of stacked xPSR. */
pulSystemCallStack[ portOFFSET_TO_PSR ] &= ( ~portPSR_STACK_PADDING_MASK );
}
}
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
void vSystemCallEnter_1( uint32_t * pulTaskStack, uint32_t ulLR ) /* PRIVILEGED_FUNCTION */
{
extern TaskHandle_t pxCurrentTCB;
xMPU_SETTINGS * pxMpuSettings;
uint32_t * pulSystemCallStack;
uint32_t ulStackFrameSize, ulSystemCallLocation, i;
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__;
extern uint32_t * __syscalls_flash_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* #if defined( __ARMCC_VERSION ) */
ulSystemCallLocation = pulTaskStack[ portOFFSET_TO_PC ];
/* If the request did not come from the system call section, do nothing. */
if( ( ulSystemCallLocation >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulSystemCallLocation <= ( uint32_t ) __syscalls_flash_end__ ) )
{
pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack;
/* This is not NULL only for the duration of the system call. */
configASSERT( pxMpuSettings->xSystemCallStackInfo.pulTaskStack == NULL );
if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL )
{
/* Extended frame i.e. FPU in use. */
ulStackFrameSize = 26;
__asm volatile (
" vpush {s0} \n" /* Trigger lazy stacking. */
" vpop {s0} \n" /* Nullify the affect of the above instruction. */
::: "memory"
);
}
else
{
/* Standard frame i.e. FPU not in use. */
ulStackFrameSize = 8;
}
/* Make space on the system call stack for the stack frame and
* the parameter passed on the stack. We only need to copy one
* parameter but we still reserve 2 spaces to keep the stack
* double word aligned. */
pulSystemCallStack = pulSystemCallStack - ulStackFrameSize - 2UL;
/* Copy the stack frame. */
for( i = 0; i < ulStackFrameSize; i++ )
{
pulSystemCallStack[ i ] = pulTaskStack[ i ];
}
/* Copy the parameter which is passed the stack. */
if( ( pulTaskStack[ portOFFSET_TO_PSR ] & portPSR_STACK_PADDING_MASK ) == portPSR_STACK_PADDING_MASK )
{
pulSystemCallStack[ ulStackFrameSize ] = pulTaskStack[ ulStackFrameSize + 1 ];
/* Record if the hardware used padding to force the stack pointer
* to be double word aligned. */
pxMpuSettings->ulTaskFlags |= portSTACK_FRAME_HAS_PADDING_FLAG;
}
else
{
pulSystemCallStack[ ulStackFrameSize ] = pulTaskStack[ ulStackFrameSize ];
/* Record if the hardware used padding to force the stack pointer
* to be double word aligned. */
pxMpuSettings->ulTaskFlags &= ( ~portSTACK_FRAME_HAS_PADDING_FLAG );
}
/* Use the pulSystemCallStack in thread mode. */
__asm volatile ( "msr psp, %0" : : "r" ( pulSystemCallStack ) );
/* Raise the privilege for the duration of the system call. */
__asm volatile (
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Clear nPRIV bit. */
" msr control, r1 \n" /* Write back new control value. */
::: "r1", "memory"
);
/* Remember the location where we should copy the stack frame when we exit from
* the system call. */
pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize;
/* Store the value of the Link Register before the SVC was raised. We need to
* restore it when we exit from the system call. */
pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry = pulTaskStack[ portOFFSET_TO_LR ];
/* We ensure in pxPortInitialiseStack that the system call stack is
* double word aligned and therefore, there is no need of padding.
* Clear the bit[9] of stacked xPSR. */
pulSystemCallStack[ portOFFSET_TO_PSR ] &= ( ~portPSR_STACK_PADDING_MASK );
}
}
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) /* PRIVILEGED_FUNCTION */
{
extern TaskHandle_t pxCurrentTCB;
xMPU_SETTINGS * pxMpuSettings;
uint32_t * pulTaskStack;
uint32_t ulStackFrameSize, ulSystemCallLocation, i;
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__;
extern uint32_t * __syscalls_flash_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* #if defined( __ARMCC_VERSION ) */
ulSystemCallLocation = pulSystemCallStack[ portOFFSET_TO_PC ];
/* If the request did not come from the system call section, do nothing. */
if( ( ulSystemCallLocation >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulSystemCallLocation <= ( uint32_t ) __syscalls_flash_end__ ) )
{
pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack;
if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL )
{
/* Extended frame i.e. FPU in use. */
ulStackFrameSize = 26;
__asm volatile (
" vpush {s0} \n" /* Trigger lazy stacking. */
" vpop {s0} \n" /* Nullify the affect of the above instruction. */
::: "memory"
);
}
else
{
/* Standard frame i.e. FPU not in use. */
ulStackFrameSize = 8;
}
/* Make space on the task stack for the stack frame. */
pulTaskStack = pulTaskStack - ulStackFrameSize;
/* Copy the stack frame. */
for( i = 0; i < ulStackFrameSize; i++ )
{
pulTaskStack[ i ] = pulSystemCallStack[ i ];
}
/* Use the pulTaskStack in thread mode. */
__asm volatile ( "msr psp, %0" : : "r" ( pulTaskStack ) );
/* Drop the privilege before returning to the thread mode. */
__asm volatile (
" mrs r1, control \n" /* Obtain current control value. */
" orr r1, #1 \n" /* Set nPRIV bit. */
" msr control, r1 \n" /* Write back new control value. */
::: "r1", "memory"
);
/* Restore the stacked link register to what it was at the time of
* system call entry. */
pulTaskStack[ portOFFSET_TO_LR ] = pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry;
/* If the hardware used padding to force the stack pointer
* to be double word aligned, set the stacked xPSR bit[9],
* otherwise clear it. */
if( ( pxMpuSettings->ulTaskFlags & portSTACK_FRAME_HAS_PADDING_FLAG ) == portSTACK_FRAME_HAS_PADDING_FLAG )
{
pulTaskStack[ portOFFSET_TO_PSR ] |= portPSR_STACK_PADDING_MASK;
}
else
{
pulTaskStack[ portOFFSET_TO_PSR ] &= ( ~portPSR_STACK_PADDING_MASK );
}
/* This is not NULL only for the duration of the system call. */
pxMpuSettings->xSystemCallStackInfo.pulTaskStack = NULL;
}
}
#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
BaseType_t xPortIsTaskPrivileged( void ) /* PRIVILEGED_FUNCTION */
{
BaseType_t xTaskIsPrivileged = pdFALSE;
const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
{
xTaskIsPrivileged = pdTRUE;
}
return xTaskIsPrivileged;
}
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
@ -738,11 +1122,19 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
( portMPU_REGION_ENABLE );
xMPUSettings->xRegionSettings[ 0 ].ulRegionStartAddress = ( uint32_t ) __SRAM_segment_start__;
xMPUSettings->xRegionSettings[ 0 ].ulRegionEndAddress = ( uint32_t ) __SRAM_segment_end__;
xMPUSettings->xRegionSettings[ 0 ].ulRegionPermissions = ( tskMPU_READ_PERMISSION |
tskMPU_WRITE_PERMISSION );
/* Invalidate user configurable regions. */
for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
{
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
xMPUSettings->xRegionSettings[ ul ].ulRegionStartAddress = 0UL;
xMPUSettings->xRegionSettings[ ul ].ulRegionEndAddress = 0UL;
xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = 0UL;
}
}
else
@ -765,6 +1157,13 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |
( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( portMPU_REGION_ENABLE );
xMPUSettings->xRegionSettings[ 0 ].ulRegionStartAddress = ( uint32_t ) pxBottomOfStack;
xMPUSettings->xRegionSettings[ 0 ].ulRegionEndAddress = ( uint32_t ) ( ( uint32_t ) ( pxBottomOfStack ) +
( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) - 1UL );
xMPUSettings->xRegionSettings[ 0 ].ulRegionPermissions = ( tskMPU_READ_PERMISSION |
tskMPU_WRITE_PERMISSION );
}
lIndex = 0;
@ -785,12 +1184,28 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |
( xRegions[ lIndex ].ulParameters ) |
( portMPU_REGION_ENABLE );
xMPUSettings->xRegionSettings[ ul ].ulRegionStartAddress = ( uint32_t) xRegions[ lIndex ].pvBaseAddress;
xMPUSettings->xRegionSettings[ ul ].ulRegionEndAddress = ( uint32_t ) ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress + xRegions[ lIndex ].ulLengthInBytes - 1UL );
xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = 0UL;
if( ( ( xRegions[ lIndex ].ulParameters & portMPU_REGION_READ_ONLY ) == portMPU_REGION_READ_ONLY ) ||
( ( xRegions[ lIndex ].ulParameters & portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ) == portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ) )
{
xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = tskMPU_READ_PERMISSION;
}
if( ( xRegions[ lIndex ].ulParameters & portMPU_REGION_READ_WRITE ) == portMPU_REGION_READ_WRITE )
{
xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = ( tskMPU_READ_PERMISSION | tskMPU_WRITE_PERMISSION );
}
}
else
{
/* Invalidate the region. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
xMPUSettings->xRegionSettings[ ul ].ulRegionStartAddress = 0UL;
xMPUSettings->xRegionSettings[ ul ].ulRegionEndAddress = 0UL;
xMPUSettings->xRegionSettings[ ul ].ulRegionPermissions = 0UL;
}
lIndex++;
@ -799,6 +1214,48 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
}
/*-----------------------------------------------------------*/
BaseType_t xPortIsAuthorizedToAccessBuffer( const void * pvBuffer,
uint32_t ulBufferLength,
uint32_t ulAccessRequested ) /* PRIVILEGED_FUNCTION */
{
uint32_t i, ulBufferStartAddress, ulBufferEndAddress;
BaseType_t xAccessGranted = pdFALSE;
const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
if( ( xTaskMpuSettings->ulTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
{
xAccessGranted = pdTRUE;
}
else
{
if( portADD_UINT32_WILL_OVERFLOW( ( ( uint32_t ) pvBuffer ), ( ulBufferLength - 1UL ) ) == pdFALSE )
{
ulBufferStartAddress = ( uint32_t ) pvBuffer;
ulBufferEndAddress = ( ( ( uint32_t ) pvBuffer ) + ulBufferLength - 1UL );
for( i = 0; i < portTOTAL_NUM_REGIONS_IN_TCB; i++ )
{
if( portIS_ADDRESS_WITHIN_RANGE( ulBufferStartAddress,
xTaskMpuSettings->xRegionSettings[ i ].ulRegionStartAddress,
xTaskMpuSettings->xRegionSettings[ i ].ulRegionEndAddress ) &&
portIS_ADDRESS_WITHIN_RANGE( ulBufferEndAddress,
xTaskMpuSettings->xRegionSettings[ i ].ulRegionStartAddress,
xTaskMpuSettings->xRegionSettings[ i ].ulRegionEndAddress ) &&
portIS_AUTHORIZED( ulAccessRequested, xTaskMpuSettings->xRegionSettings[ i ].ulRegionPermissions ) )
{
xAccessGranted = pdTRUE;
break;
}
}
}
}
return xAccessGranted;
}
/*-----------------------------------------------------------*/
#if ( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )