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

File diff suppressed because it is too large Load diff

View file

@ -107,6 +107,13 @@
#define portPRIGROUP_SHIFT ( 8UL )
/*-----------------------------------------------------------*/
/**
* @brief Constants used during system call enter and exit.
*/
#define portPSR_STACK_PADDING_MASK ( 1UL << 9UL )
#define portEXC_RETURN_STACK_FRAME_TYPE_MASK ( 1UL << 4UL )
/*-----------------------------------------------------------*/
/**
* @brief Constants required to manipulate the FPU.
*/
@ -123,6 +130,14 @@
#define portFPCCR_LSPEN_MASK ( 1UL << portFPCCR_LSPEN_POS )
/*-----------------------------------------------------------*/
/**
* @brief 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 )
/*-----------------------------------------------------------*/
/**
* @brief Constants required to manipulate the MPU.
*/
@ -148,6 +163,8 @@
#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */
#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */
#define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL )
#define portMPU_MAIR_ATTR0_POS ( 0UL )
#define portMPU_MAIR_ATTR0_MASK ( 0x000000ff )
@ -191,6 +208,30 @@
/* Expected value of the portMPU_TYPE register. */
#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL )
/* Extract first address of the MPU region as encoded in the
* RBAR (Region Base Address Register) value. */
#define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \
( ( rbar ) & portMPU_RBAR_ADDRESS_MASK )
/* Extract last address of the MPU region as encoded in the
* RLAR (Region Limit Address Register) value. */
#define portEXTRACT_LAST_ADDRESS_FROM_RLAR( rlar ) \
( ( ( rlar ) & portMPU_RLAR_ADDRESS_MASK ) | ~portMPU_RLAR_ADDRESS_MASK )
/* Does addr lies 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 ) ) )
/*-----------------------------------------------------------*/
/**
@ -311,6 +352,19 @@ static void prvTaskExitError( void );
#if ( configENABLE_MPU == 1 )
/**
* @brief Extract MPU region's access permissions from the Region Base Address
* Register (RBAR) value.
*
* @param ulRBARValue RBAR value for the MPU region.
*
* @return uint32_t Access permissions.
*/
static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION;
#endif /* configENABLE_MPU */
#if ( configENABLE_MPU == 1 )
/**
* @brief Setup the Memory Protection Unit (MPU).
*/
@ -365,6 +419,60 @@ void SysTick_Handler( void ) PRIVILEGED_FUNCTION;
* @brief C part of SVC handler.
*/
portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIVILEGED_FUNCTION;
#if ( ( configENABLE_MPU == 1 ) && ( 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 /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
#if ( ( configENABLE_MPU == 1 ) && ( 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 /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
#if ( ( configENABLE_MPU == 1 ) && ( 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 /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
#if ( configENABLE_MPU == 1 )
/**
* @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;
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
/**
@ -681,6 +789,26 @@ static void prvTaskExitError( void )
}
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) /* PRIVILEGED_FUNCTION */
{
uint32_t ulAccessPermissions = 0;
if( ( ulRBARValue & portMPU_RBAR_ACCESS_PERMISSIONS_MASK ) == portMPU_REGION_READ_ONLY )
{
ulAccessPermissions = tskMPU_READ_PERMISSION;
}
if( ( ulRBARValue & portMPU_RBAR_ACCESS_PERMISSIONS_MASK ) == portMPU_REGION_READ_WRITE )
{
ulAccessPermissions = ( tskMPU_READ_PERMISSION | tskMPU_WRITE_PERMISSION );
}
return ulAccessPermissions;
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
static void prvSetupMPU( void ) /* PRIVILEGED_FUNCTION */
{
@ -853,7 +981,7 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTION portDONT_DISCARD */
{
#if ( configENABLE_MPU == 1 )
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) )
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
@ -865,7 +993,7 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* defined( __ARMCC_VERSION ) */
#endif /* configENABLE_MPU */
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */
uint32_t ulPC;
@ -880,7 +1008,7 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
/* Register are stored on the stack in the following order - R0, R1, R2, R3,
* R12, LR, PC, xPSR. */
ulPC = pulCallerStackAddress[ 6 ];
ulPC = pulCallerStackAddress[ portOFFSET_TO_PC ];
ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
switch( ucSVCNumber )
@ -951,18 +1079,18 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
vRestoreContextOfFirstTask();
break;
#if ( configENABLE_MPU == 1 )
case portSVC_RAISE_PRIVILEGE:
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) )
case portSVC_RAISE_PRIVILEGE:
/* Only raise the privilege, if the svc was raised from any of
* the system calls. */
if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
{
vRaisePrivilege();
}
break;
#endif /* configENABLE_MPU */
/* Only raise the privilege, if the svc was raised from any of
* the system calls. */
if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
{
vRaisePrivilege();
}
break;
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */
default:
/* Incorrect SVC call. */
@ -971,51 +1099,455 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
}
/*-----------------------------------------------------------*/
/* *INDENT-OFF* */
#if ( ( configENABLE_MPU == 1 ) && ( 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 ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
{
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;
}
}
#else
{
ulStackFrameSize = 8;
}
#endif /* configENABLE_FPU || configENABLE_MVE */
/* 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 ];
}
/* Store the value of the LR and PSPLIM registers before the SVC was raised. We need to
* restore it when we exit from the system call. */
pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry = pulTaskStack[ portOFFSET_TO_LR ];
__asm volatile ( "mrs %0, psplim" : "=r" ( pxMpuSettings->xSystemCallStackInfo.ulStackLimitRegisterAtSystemCallEntry ) );
/* Use the pulSystemCallStack in thread mode. */
__asm volatile ( "msr psp, %0" : : "r" ( pulSystemCallStack ) );
__asm volatile ( "msr psplim, %0" : : "r" ( pxMpuSettings->xSystemCallStackInfo.pulSystemCallStackLimit ) );
/* Remember the location where we should copy the stack frame when we exit from
* the system call. */
pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize;
/* 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 );
/* Raise the privilege for the duration of the system call. */
__asm volatile (
" mrs r0, control \n" /* Obtain current control value. */
" movs r1, #1 \n" /* r1 = 1. */
" bics r0, r1 \n" /* Clear nPRIV bit. */
" msr control, r0 \n" /* Write back new control value. */
::: "r0", "r1", "memory"
);
}
}
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
#if ( ( configENABLE_MPU == 1 ) && ( 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 ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
{
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;
}
}
#else
{
ulStackFrameSize = 8;
}
#endif /* configENABLE_FPU || configENABLE_MVE */
/* 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 );
}
/* Store the value of the LR and PSPLIM registers before the SVC was raised.
* We need to restore it when we exit from the system call. */
pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry = pulTaskStack[ portOFFSET_TO_LR ];
__asm volatile ( "mrs %0, psplim" : "=r" ( pxMpuSettings->xSystemCallStackInfo.ulStackLimitRegisterAtSystemCallEntry ) );
/* Use the pulSystemCallStack in thread mode. */
__asm volatile ( "msr psp, %0" : : "r" ( pulSystemCallStack ) );
__asm volatile ( "msr psplim, %0" : : "r" ( pxMpuSettings->xSystemCallStackInfo.pulSystemCallStackLimit ) );
/* Remember the location where we should copy the stack frame when we exit from
* the system call. */
pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize;
/* 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 );
/* Raise the privilege for the duration of the system call. */
__asm volatile (
" mrs r0, control \n" /* Obtain current control value. */
" movs r1, #1 \n" /* r1 = 1. */
" bics r0, r1 \n" /* Clear nPRIV bit. */
" msr control, r0 \n" /* Write back new control value. */
::: "r0", "r1", "memory"
);
}
}
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
#if ( ( configENABLE_MPU == 1 ) && ( 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 ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
{
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;
}
}
#else
{
ulStackFrameSize = 8;
}
#endif /* configENABLE_FPU || configENABLE_MVE */
/* 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 ) );
/* Restore the LR and PSPLIM to what they were at the time of
* system call entry. */
pulTaskStack[ portOFFSET_TO_LR ] = pxMpuSettings->xSystemCallStackInfo.ulLinkRegisterAtSystemCallEntry;
__asm volatile ( "msr psplim, %0" : : "r" ( pxMpuSettings->xSystemCallStackInfo.ulStackLimitRegisterAtSystemCallEntry ) );
/* 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;
/* Drop the privilege before returning to the thread mode. */
__asm volatile (
" mrs r0, control \n" /* Obtain current control value. */
" movs r1, #1 \n" /* r1 = 1. */
" orrs r0, r1 \n" /* Set nPRIV bit. */
" msr control, r0 \n" /* Write back new control value. */
::: "r0", "r1", "memory"
);
}
}
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged ) /* PRIVILEGED_FUNCTION */
#else
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters ) /* PRIVILEGED_FUNCTION */
#endif /* configENABLE_MPU */
/* *INDENT-ON* */
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;
}
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
#if( configENABLE_MPU == 1 )
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged,
xMPU_SETTINGS * xMPUSettings ) /* PRIVILEGED_FUNCTION */
{
uint32_t ulIndex = 0;
xMPUSettings->ulContext[ ulIndex ] = 0x04040404; /* r4. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x05050505; /* r5. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x06060606; /* r6. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x07070707; /* r7. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x08080808; /* r8. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x09090909; /* r9. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x10101010; /* r10. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */
ulIndex++;
#if ( configENABLE_TRUSTZONE == 1 )
{
xMPUSettings->ulContext[ ulIndex ] = portNO_SECURE_CONTEXT; /* xSecureContext. */
ulIndex++;
}
#endif /* configENABLE_TRUSTZONE */
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */
ulIndex++;
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */
ulIndex++;
if( xRunPrivileged == pdTRUE )
{
xMPUSettings->ulTaskFlags |= portTASK_IS_PRIVILEGED_FLAG;
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portINITIAL_CONTROL_PRIVILEGED; /* CONTROL. */
ulIndex++;
}
else
{
xMPUSettings->ulTaskFlags &= ( ~portTASK_IS_PRIVILEGED_FLAG );
xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portINITIAL_CONTROL_UNPRIVILEGED; /* CONTROL. */
ulIndex++;
}
xMPUSettings->ulContext[ ulIndex ] = portINITIAL_EXC_RETURN; /* LR (EXC_RETURN). */
ulIndex++;
#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 ) ) );
xMPUSettings->xSystemCallStackInfo.pulSystemCallStackLimit = &( xMPUSettings->xSystemCallStackInfo.ulSystemCallStackBuffer[ 0 ] );
xMPUSettings->xSystemCallStackInfo.pulSystemCallStackLimit = ( uint32_t * ) ( ( ( uint32_t ) ( xMPUSettings->xSystemCallStackInfo.pulSystemCallStackLimit ) +
( uint32_t ) ( portBYTE_ALIGNMENT - 1 ) ) &
( uint32_t ) ( ~( portBYTE_ALIGNMENT_MASK ) ) );
/* This is not NULL only for the duration of a system call. */
xMPUSettings->xSystemCallStackInfo.pulTaskStack = NULL;
}
#endif /* configUSE_MPU_WRAPPERS_V1 == 0 */
return &( xMPUSettings->ulContext[ ulIndex ] );
}
#else /* configENABLE_MPU */
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters ) /* PRIVILEGED_FUNCTION */
{
/* Simulate the stack frame as it would be created by a context switch
* interrupt. */
#if ( portPRELOAD_REGISTERS == 0 )
{
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxCode; /* PC */
*pxTopOfStack = ( StackType_t ) pxCode; /* PC. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */
pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */
*pxTopOfStack = portINITIAL_EXC_RETURN;
#if ( configENABLE_MPU == 1 )
{
pxTopOfStack--;
if( xRunPrivileged == pdTRUE )
{
*pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */
}
else
{
*pxTopOfStack = portINITIAL_CONTROL_UNPRIVILEGED; /* Slot used to hold this task's CONTROL value. */
}
}
#endif /* configENABLE_MPU */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */
@ -1029,55 +1561,39 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
#else /* portPRELOAD_REGISTERS */
{
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxCode; /* PC */
*pxTopOfStack = ( StackType_t ) pxCode; /* PC. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12 */
*pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3 */
*pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2 */
*pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1 */
*pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11 */
*pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10 */
*pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09 */
*pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08 */
*pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07 */
*pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06 */
*pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05 */
*pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04 */
*pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN */
#if ( configENABLE_MPU == 1 )
{
pxTopOfStack--;
if( xRunPrivileged == pdTRUE )
{
*pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */
}
else
{
*pxTopOfStack = portINITIAL_CONTROL_UNPRIVILEGED; /* Slot used to hold this task's CONTROL value. */
}
}
#endif /* configENABLE_MPU */
*pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */
@ -1092,6 +1608,8 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
return pxTopOfStack;
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
@ -1347,6 +1865,54 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
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; i++ )
{
/* Is the MPU region enabled? */
if( ( xTaskMpuSettings->xRegionsSettings[ i ].ulRLAR & portMPU_RLAR_REGION_ENABLE ) == portMPU_RLAR_REGION_ENABLE )
{
if( portIS_ADDRESS_WITHIN_RANGE( ulBufferStartAddress,
portEXTRACT_FIRST_ADDRESS_FROM_RBAR( xTaskMpuSettings->xRegionsSettings[ i ].ulRBAR ),
portEXTRACT_LAST_ADDRESS_FROM_RLAR( xTaskMpuSettings->xRegionsSettings[ i ].ulRLAR ) ) &&
portIS_ADDRESS_WITHIN_RANGE( ulBufferEndAddress,
portEXTRACT_FIRST_ADDRESS_FROM_RBAR( xTaskMpuSettings->xRegionsSettings[ i ].ulRBAR ),
portEXTRACT_LAST_ADDRESS_FROM_RLAR( xTaskMpuSettings->xRegionsSettings[ i ].ulRLAR ) ) &&
portIS_AUTHORIZED( ulAccessRequested,
prvGetRegionAccessPermissions( xTaskMpuSettings->xRegionsSettings[ i ].ulRBAR ) ) )
{
xAccessGranted = pdTRUE;
break;
}
}
}
}
}
return xAccessGranted;
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;

View file

@ -40,95 +40,120 @@
* header files. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configENABLE_MPU == 1 )
void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" program_mpu_first_task: \n"
" ldr r3, pxCurrentTCBConst2 \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r3] \n" /* r0 = pxCurrentTCB. */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r1, xMPUCTRLConst2 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" bic r2, #1 \n" /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
" str r2, [r1] \n" /* Disable MPU. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
" ldr r1, [r0] \n" /* r1 = *r0 i.e. r1 = MAIR0. */
" ldr r2, xMAIR0Const2 \n" /* r2 = 0xe000edc0 [Location of MAIR0]. */
" str r1, [r2] \n" /* Program MAIR0. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
" ldr r1, xRNRConst2 \n" /* r1 = 0xe000ed98 [Location of RNR]. */
" ldr r2, xRBARConst2 \n" /* r2 = 0xe000ed9c [Location of RBAR]. */
" \n"
" movs r3, #4 \n" /* r3 = 4. */
" str r3, [r1] \n" /* Program RNR = 4. */
" ldmia r0!, {r4-r11} \n" /* Read 4 set of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" \n"
#if ( configTOTAL_MPU_REGIONS == 16 )
" movs r3, #8 \n" /* r3 = 8. */
" str r3, [r1] \n" /* Program RNR = 8. */
" ldmia r0!, {r4-r11} \n" /* Read 4 set of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" movs r3, #12 \n" /* r3 = 12. */
" str r3, [r1] \n" /* Program RNR = 12. */
" ldmia r0!, {r4-r11} \n" /* Read 4 set of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
#endif /* configTOTAL_MPU_REGIONS == 16 */
" \n"
" ldr r1, xMPUCTRLConst2 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" orr r2, #1 \n" /* r2 = r1 | 1 i.e. Set the bit 0 in r2. */
" str r2, [r1] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" restore_context_first_task: \n"
" ldr r3, pxCurrentTCBConst2 \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n" /* r1 = pxCurrentTCB.*/
" ldr r2, [r1] \n" /* r2 = Location of saved context in TCB. */
" \n"
" restore_special_regs_first_task: \n"
" ldmdb r2!, {r0, r3-r5, lr} \n" /* r0 = xSecureContext, r3 = original PSP, r4 = PSPLIM, r5 = CONTROL, LR restored. */
" msr psp, r3 \n"
" msr psplim, r4 \n"
" msr control, r5 \n"
" ldr r4, xSecureContextConst2 \n" /* Read the location of xSecureContext i.e. &( xSecureContext ). */
" str r0, [r4] \n" /* Restore xSecureContext. */
" \n"
" restore_general_regs_first_task: \n"
" ldmdb r2!, {r4-r11} \n" /* r4-r11 contain hardware saved context. */
" stmia r3!, {r4-r11} \n" /* Copy the hardware saved context on the task stack. */
" ldmdb r2!, {r4-r11} \n" /* r4-r11 restored. */
" \n"
" restore_context_done_first_task: \n"
" str r2, [r1] \n" /* Save the location where the context should be saved next as the first member of TCB. */
" mov r0, #0 \n"
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
" bx lr \n"
" \n"
" .align 4 \n"
" pxCurrentTCBConst2: .word pxCurrentTCB \n"
" xSecureContextConst2: .word xSecureContext \n"
" xMPUCTRLConst2: .word 0xe000ed94 \n"
" xMAIR0Const2: .word 0xe000edc0 \n"
" xRNRConst2: .word 0xe000ed98 \n"
" xRBARConst2: .word 0xe000ed9c \n"
);
}
#else /* configENABLE_MPU */
void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" ldr r2, pxCurrentTCBConst2 \n"/* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r3, [r2] \n"/* Read pxCurrentTCB. */
" ldr r0, [r3] \n"/* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
" \n"
#if ( configENABLE_MPU == 1 )
" dmb \n"/* Complete outstanding transfers before disabling MPU. */
" ldr r2, xMPUCTRLConst2 \n"/* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r4, [r2] \n"/* Read the value of MPU_CTRL. */
" bic r4, #1 \n"/* r4 = r4 & ~1 i.e. Clear the bit 0 in r4. */
" str r4, [r2] \n"/* Disable MPU. */
" \n"
" adds r3, #4 \n"/* r3 = r3 + 4. r3 now points to MAIR0 in TCB. */
" ldr r4, [r3] \n"/* r4 = *r3 i.e. r4 = MAIR0. */
" ldr r2, xMAIR0Const2 \n"/* r2 = 0xe000edc0 [Location of MAIR0]. */
" str r4, [r2] \n"/* Program MAIR0. */
" ldr r2, xRNRConst2 \n"/* r2 = 0xe000ed98 [Location of RNR]. */
" movs r4, #4 \n"/* r4 = 4. */
" str r4, [r2] \n"/* Program RNR = 4. */
" adds r3, #4 \n"/* r3 = r3 + 4. r3 now points to first RBAR in TCB. */
" ldr r2, xRBARConst2 \n"/* r2 = 0xe000ed9c [Location of RBAR]. */
" ldmia r3!, {r4-r11} \n"/* Read 4 set of RBAR/RLAR registers from TCB. */
" stmia r2!, {r4-r11} \n"/* Write 4 set of RBAR/RLAR registers using alias registers. */
" \n"
#if ( configTOTAL_MPU_REGIONS == 16 )
" ldr r2, xRNRConst2 \n"/* r2 = 0xe000ed98 [Location of RNR]. */
" movs r4, #8 \n"/* r4 = 8. */
" str r4, [r2] \n"/* Program RNR = 8. */
" ldr r2, xRBARConst2 \n"/* r2 = 0xe000ed9c [Location of RBAR]. */
" ldmia r3!, {r4-r11} \n"/* Read 4 set of RBAR/RLAR registers from TCB. */
" stmia r2!, {r4-r11} \n"/* Write 4 set of RBAR/RLAR registers using alias registers. */
" ldr r2, xRNRConst2 \n"/* r2 = 0xe000ed98 [Location of RNR]. */
" movs r4, #12 \n"/* r4 = 12. */
" str r4, [r2] \n"/* Program RNR = 12. */
" ldr r2, xRBARConst2 \n"/* r2 = 0xe000ed9c [Location of RBAR]. */
" ldmia r3!, {r4-r11} \n"/* Read 4 set of RBAR/RLAR registers from TCB. */
" stmia r2!, {r4-r11} \n"/* Write 4 set of RBAR/RLAR registers using alias registers. */
#endif /* configTOTAL_MPU_REGIONS == 16 */
" \n"
" ldr r2, xMPUCTRLConst2 \n"/* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r4, [r2] \n"/* Read the value of MPU_CTRL. */
" orr r4, #1 \n"/* r4 = r4 | 1 i.e. Set the bit 0 in r4. */
" str r4, [r2] \n"/* Enable MPU. */
" dsb \n"/* Force memory writes before continuing. */
#endif /* configENABLE_MPU */
" \n"
#if ( configENABLE_MPU == 1 )
" ldm r0!, {r1-r4} \n"/* Read from stack - r1 = xSecureContext, r2 = PSPLIM, r3 = CONTROL and r4 = EXC_RETURN. */
" ldr r5, xSecureContextConst2 \n"
" str r1, [r5] \n"/* Set xSecureContext to this task's value for the same. */
" msr psplim, r2 \n"/* Set this task's PSPLIM value. */
" msr control, r3 \n"/* Set this task's CONTROL value. */
" adds r0, #32 \n"/* Discard everything up to r0. */
" msr psp, r0 \n"/* This is now the new top of stack to use in the task. */
" isb \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"/* Ensure that interrupts are enabled when the first task starts. */
" bx r4 \n"/* Finally, branch to EXC_RETURN. */
#else /* configENABLE_MPU */
" ldm r0!, {r1-r3} \n"/* Read from stack - r1 = xSecureContext, r2 = PSPLIM and r3 = EXC_RETURN. */
" ldr r4, xSecureContextConst2 \n"
" str r1, [r4] \n"/* Set xSecureContext to this task's value for the same. */
" msr psplim, r2 \n"/* Set this task's PSPLIM value. */
" movs r1, #2 \n"/* r1 = 2. */
" msr CONTROL, r1 \n"/* Switch to use PSP in the thread mode. */
" adds r0, #32 \n"/* Discard everything up to r0. */
" msr psp, r0 \n"/* This is now the new top of stack to use in the task. */
" isb \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"/* Ensure that interrupts are enabled when the first task starts. */
" bx r3 \n"/* Finally, branch to EXC_RETURN. */
#endif /* configENABLE_MPU */
" ldr r2, pxCurrentTCBConst2 \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r3, [r2] \n" /* Read pxCurrentTCB. */
" ldr r0, [r3] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
" \n"
" ldm r0!, {r1-r3} \n" /* Read from stack - r1 = xSecureContext, r2 = PSPLIM and r3 = EXC_RETURN. */
" ldr r4, xSecureContextConst2 \n"
" str r1, [r4] \n" /* Set xSecureContext to this task's value for the same. */
" msr psplim, r2 \n" /* Set this task's PSPLIM value. */
" movs r1, #2 \n" /* r1 = 2. */
" msr CONTROL, r1 \n" /* Switch to use PSP in the thread mode. */
" adds r0, #32 \n" /* Discard everything up to r0. */
" msr psp, r0 \n" /* This is now the new top of stack to use in the task. */
" isb \n"
" mov r0, #0 \n"
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
" bx r3 \n" /* Finally, branch to EXC_RETURN. */
" .align 4 \n"
"pxCurrentTCBConst2: .word pxCurrentTCB \n"
"xSecureContextConst2: .word xSecureContext \n"
#if ( configENABLE_MPU == 1 )
"xMPUCTRLConst2: .word 0xe000ed94 \n"
"xMAIR0Const2: .word 0xe000edc0 \n"
"xRNRConst2: .word 0xe000ed98 \n"
"xRBARConst2: .word 0xe000ed9c \n"
#endif /* configENABLE_MPU */
);
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */
@ -236,6 +261,160 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
}
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" .extern SecureContext_SaveContext \n"
" .extern SecureContext_LoadContext \n"
" \n"
" ldr r3, xSecureContextConst \n" /* Read the location of xSecureContext i.e. &( xSecureContext ). */
" ldr r0, [r3] \n" /* Read xSecureContext - Value of xSecureContext must be in r0 as it is used as a parameter later. */
" ldr r3, pxCurrentTCBConst \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n" /* Read pxCurrentTCB - Value of pxCurrentTCB must be in r1 as it is used as a parameter later. */
" ldr r2, [r1] \n" /* r2 = Location in TCB where the context should be saved. */
" \n"
" cbz r0, save_ns_context \n" /* No secure context to save. */
" save_s_context: \n"
" push {r0-r2, lr} \n"
" bl SecureContext_SaveContext \n" /* Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
" pop {r0-r2, lr} \n"
" \n"
" save_ns_context: \n"
" mov r3, lr \n" /* r3 = LR (EXC_RETURN). */
" lsls r3, r3, #25 \n" /* r3 = r3 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
" bmi save_special_regs \n" /* r3 < 0 ==> Bit[6] in EXC_RETURN is 1 ==> secure stack was used to store the stack frame. */
" \n"
" save_general_regs: \n"
" mrs r3, psp \n"
" \n"
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
" add r3, r3, #0x20 \n" /* Move r3 to location where s0 is saved. */
" tst lr, #0x10 \n"
" ittt eq \n"
" vstmiaeq r2!, {s16-s31} \n" /* Store s16-s31. */
" vldmiaeq r3, {s0-s16} \n" /* Copy hardware saved FP context into s0-s16. */
" vstmiaeq r2!, {s0-s16} \n" /* Store hardware saved FP context. */
" sub r3, r3, #0x20 \n" /* Set r3 back to the location of hardware saved context. */
#endif /* configENABLE_FPU || configENABLE_MVE */
" \n"
" stmia r2!, {r4-r11} \n" /* Store r4-r11. */
" ldmia r3, {r4-r11} \n" /* Copy the hardware saved context into r4-r11. */
" stmia r2!, {r4-r11} \n" /* Store the hardware saved context. */
" \n"
" save_special_regs: \n"
" mrs r3, psp \n" /* r3 = PSP. */
" mrs r4, psplim \n" /* r4 = PSPLIM. */
" mrs r5, control \n" /* r5 = CONTROL. */
" stmia r2!, {r0, r3-r5, lr} \n" /* Store xSecureContext, original PSP (after hardware has saved context), PSPLIM, CONTROL and LR. */
" str r2, [r1] \n" /* Save the location from where the context should be restored as the first member of TCB. */
" \n"
" select_next_task: \n"
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
" msr basepri, r0 \n" /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n" /* r0 = 0. */
" msr basepri, r0 \n" /* Enable interrupts. */
" \n"
" program_mpu: \n"
" ldr r3, pxCurrentTCBConst \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r3] \n" /* r0 = pxCurrentTCB.*/
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r1, xMPUCTRLConst \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" bic r2, #1 \n" /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
" str r2, [r1] \n" /* Disable MPU. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
" ldr r1, [r0] \n" /* r1 = *r0 i.e. r1 = MAIR0. */
" ldr r2, xMAIR0Const \n" /* r2 = 0xe000edc0 [Location of MAIR0]. */
" str r1, [r2] \n" /* Program MAIR0. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
" ldr r1, xRNRConst \n" /* r1 = 0xe000ed98 [Location of RNR]. */
" ldr r2, xRBARConst \n" /* r2 = 0xe000ed9c [Location of RBAR]. */
" \n"
" movs r3, #4 \n" /* r3 = 4. */
" str r3, [r1] \n" /* Program RNR = 4. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" \n"
#if ( configTOTAL_MPU_REGIONS == 16 )
" movs r3, #8 \n" /* r3 = 8. */
" str r3, [r1] \n" /* Program RNR = 8. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" movs r3, #12 \n" /* r3 = 12. */
" str r3, [r1] \n" /* Program RNR = 12. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
#endif /* configTOTAL_MPU_REGIONS == 16 */
" \n"
" ldr r1, xMPUCTRLConst \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" orr r2, #1 \n" /* r2 = r2 | 1 i.e. Set the bit 0 in r2. */
" str r2, [r1] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" restore_context: \n"
" ldr r3, pxCurrentTCBConst \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n" /* r1 = pxCurrentTCB.*/
" ldr r2, [r1] \n" /* r2 = Location of saved context in TCB. */
" \n"
" restore_special_regs: \n"
" ldmdb r2!, {r0, r3-r5, lr} \n" /* r0 = xSecureContext, r3 = original PSP, r4 = PSPLIM, r5 = CONTROL, LR restored. */
" msr psp, r3 \n"
" msr psplim, r4 \n"
" msr control, r5 \n"
" ldr r4, xSecureContextConst \n" /* Read the location of xSecureContext i.e. &( xSecureContext ). */
" str r0, [r4] \n" /* Restore xSecureContext. */
" cbz r0, restore_ns_context \n" /* No secure context to restore. */
" \n"
" restore_s_context: \n"
" push {r1-r3, lr} \n"
" bl SecureContext_LoadContext \n" /* Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
" pop {r1-r3, lr} \n"
" \n"
" restore_ns_context: \n"
" mov r0, lr \n" /* r0 = LR (EXC_RETURN). */
" lsls r0, r0, #25 \n" /* r0 = r0 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
" bmi restore_context_done \n" /* r0 < 0 ==> Bit[6] in EXC_RETURN is 1 ==> secure stack was used to store the stack frame. */
" \n"
" restore_general_regs: \n"
" ldmdb r2!, {r4-r11} \n" /* r4-r11 contain hardware saved context. */
" stmia r3!, {r4-r11} \n" /* Copy the hardware saved context on the task stack. */
" ldmdb r2!, {r4-r11} \n" /* r4-r11 restored. */
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
" tst lr, #0x10 \n"
" ittt eq \n"
" vldmdbeq r2!, {s0-s16} \n" /* s0-s16 contain hardware saved FP context. */
" vstmiaeq r3!, {s0-s16} \n" /* Copy hardware saved FP context on the task stack. */
" vldmdbeq r2!, {s16-s31} \n" /* Restore s16-s31. */
#endif /* configENABLE_FPU || configENABLE_MVE */
" \n"
" restore_context_done: \n"
" str r2, [r1] \n" /* Save the location where the context should be saved next as the first member of TCB. */
" bx lr \n"
" \n"
" .align 4 \n"
" pxCurrentTCBConst: .word pxCurrentTCB \n"
" xSecureContextConst: .word xSecureContext \n"
" xMPUCTRLConst: .word 0xe000ed94 \n"
" xMAIR0Const: .word 0xe000edc0 \n"
" xRNRConst: .word 0xe000ed98 \n"
" xRBARConst: .word 0xe000ed9c \n"
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
#else /* configENABLE_MPU */
void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
@ -260,20 +439,11 @@ void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
" \n"
" ldr r3, pxCurrentTCBConst \n"/* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n"/* Read pxCurrentTCB.*/
#if ( configENABLE_MPU == 1 )
" subs r2, r2, #16 \n"/* Make space for xSecureContext, PSPLIM, CONTROL and LR on the stack. */
" str r2, [r1] \n"/* Save the new top of stack in TCB. */
" mrs r1, psplim \n"/* r1 = PSPLIM. */
" mrs r3, control \n"/* r3 = CONTROL. */
" mov r4, lr \n"/* r4 = LR/EXC_RETURN. */
" stmia r2!, {r0, r1, r3, r4} \n"/* Store xSecureContext, PSPLIM, CONTROL and LR on the stack. */
#else /* configENABLE_MPU */
" subs r2, r2, #12 \n"/* Make space for xSecureContext, PSPLIM and LR on the stack. */
" str r2, [r1] \n"/* Save the new top of stack in TCB. */
" mrs r1, psplim \n"/* r1 = PSPLIM. */
" mov r3, lr \n"/* r3 = LR/EXC_RETURN. */
" stmia r2!, {r0, r1, r3} \n"/* Store xSecureContext, PSPLIM and LR on the stack. */
#endif /* configENABLE_MPU */
" subs r2, r2, #12 \n"/* Make space for xSecureContext, PSPLIM and LR on the stack. */
" str r2, [r1] \n"/* Save the new top of stack in TCB. */
" mrs r1, psplim \n"/* r1 = PSPLIM. */
" mov r3, lr \n"/* r3 = LR/EXC_RETURN. */
" stmia r2!, {r0, r1, r3} \n"/* Store xSecureContext, PSPLIM and LR on the stack. */
" b select_next_task \n"
" \n"
" save_ns_context: \n"
@ -284,26 +454,14 @@ void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
" it eq \n"
" vstmdbeq r2!, {s16-s31} \n"/* Store the additional FP context registers which are not saved automatically. */
#endif /* configENABLE_FPU || configENABLE_MVE */
#if ( configENABLE_MPU == 1 )
" subs r2, r2, #48 \n"/* Make space for xSecureContext, PSPLIM, CONTROL, LR and the remaining registers on the stack. */
" str r2, [r1] \n"/* Save the new top of stack in TCB. */
" adds r2, r2, #16 \n"/* r2 = r2 + 16. */
" stm r2, {r4-r11} \n"/* Store the registers that are not saved automatically. */
" mrs r1, psplim \n"/* r1 = PSPLIM. */
" mrs r3, control \n"/* r3 = CONTROL. */
" mov r4, lr \n"/* r4 = LR/EXC_RETURN. */
" subs r2, r2, #16 \n"/* r2 = r2 - 16. */
" stmia r2!, {r0, r1, r3, r4} \n"/* Store xSecureContext, PSPLIM, CONTROL and LR on the stack. */
#else /* configENABLE_MPU */
" subs r2, r2, #44 \n"/* Make space for xSecureContext, PSPLIM, LR and the remaining registers on the stack. */
" str r2, [r1] \n"/* Save the new top of stack in TCB. */
" adds r2, r2, #12 \n"/* r2 = r2 + 12. */
" stm r2, {r4-r11} \n"/* Store the registers that are not saved automatically. */
" mrs r1, psplim \n"/* r1 = PSPLIM. */
" mov r3, lr \n"/* r3 = LR/EXC_RETURN. */
" subs r2, r2, #12 \n"/* r2 = r2 - 12. */
" stmia r2!, {r0, r1, r3} \n"/* Store xSecureContext, PSPLIM and LR on the stack. */
#endif /* configENABLE_MPU */
" subs r2, r2, #44 \n"/* Make space for xSecureContext, PSPLIM, LR and the remaining registers on the stack. */
" str r2, [r1] \n"/* Save the new top of stack in TCB. */
" adds r2, r2, #12 \n"/* r2 = r2 + 12. */
" stm r2, {r4-r11} \n"/* Store the registers that are not saved automatically. */
" mrs r1, psplim \n"/* r1 = PSPLIM. */
" mov r3, lr \n"/* r3 = LR/EXC_RETURN. */
" subs r2, r2, #12 \n"/* r2 = r2 - 12. */
" stmia r2!, {r0, r1, r3} \n"/* Store xSecureContext, PSPLIM and LR on the stack. */
" \n"
" select_next_task: \n"
" mov r0, %0 \n"/* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
@ -318,83 +476,22 @@ void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
" ldr r1, [r3] \n"/* Read pxCurrentTCB. */
" ldr r2, [r1] \n"/* The first item in pxCurrentTCB is the task top of stack. r2 now points to the top of stack. */
" \n"
#if ( configENABLE_MPU == 1 )
" dmb \n"/* Complete outstanding transfers before disabling MPU. */
" ldr r3, xMPUCTRLConst \n"/* r3 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r4, [r3] \n"/* Read the value of MPU_CTRL. */
" bic r4, #1 \n"/* r4 = r4 & ~1 i.e. Clear the bit 0 in r4. */
" str r4, [r3] \n"/* Disable MPU. */
" \n"
" adds r1, #4 \n"/* r1 = r1 + 4. r1 now points to MAIR0 in TCB. */
" ldr r4, [r1] \n"/* r4 = *r1 i.e. r4 = MAIR0. */
" ldr r3, xMAIR0Const \n"/* r3 = 0xe000edc0 [Location of MAIR0]. */
" str r4, [r3] \n"/* Program MAIR0. */
" ldr r3, xRNRConst \n"/* r3 = 0xe000ed98 [Location of RNR]. */
" movs r4, #4 \n"/* r4 = 4. */
" str r4, [r3] \n"/* Program RNR = 4. */
" adds r1, #4 \n"/* r1 = r1 + 4. r1 now points to first RBAR in TCB. */
" ldr r3, xRBARConst \n"/* r3 = 0xe000ed9c [Location of RBAR]. */
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r3!, {r4-r11} \n"/* Write 4 set of RBAR/RLAR registers using alias registers. */
" \n"
#if ( configTOTAL_MPU_REGIONS == 16 )
" ldr r3, xRNRConst \n"/* r3 = 0xe000ed98 [Location of RNR]. */
" movs r4, #8 \n"/* r4 = 8. */
" str r4, [r3] \n"/* Program RNR = 8. */
" ldr r3, xRBARConst \n"/* r3 = 0xe000ed9c [Location of RBAR]. */
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r3!, {r4-r11} \n"/* Write 4 set of RBAR/RLAR registers using alias registers. */
" ldr r3, xRNRConst \n"/* r3 = 0xe000ed98 [Location of RNR]. */
" movs r4, #12 \n"/* r4 = 12. */
" str r4, [r3] \n"/* Program RNR = 12. */
" ldr r3, xRBARConst \n"/* r3 = 0xe000ed9c [Location of RBAR]. */
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r3!, {r4-r11} \n"/* Write 4 set of RBAR/RLAR registers using alias registers. */
#endif /* configTOTAL_MPU_REGIONS == 16 */
" \n"
" ldr r3, xMPUCTRLConst \n"/* r3 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r4, [r3] \n"/* Read the value of MPU_CTRL. */
" orr r4, #1 \n"/* r4 = r4 | 1 i.e. Set the bit 0 in r4. */
" str r4, [r3] \n"/* Enable MPU. */
" dsb \n"/* Force memory writes before continuing. */
#endif /* configENABLE_MPU */
" \n"
#if ( configENABLE_MPU == 1 )
" ldmia r2!, {r0, r1, r3, r4} \n"/* Read from stack - r0 = xSecureContext, r1 = PSPLIM, r3 = CONTROL and r4 = LR. */
" msr psplim, r1 \n"/* Restore the PSPLIM register value for the task. */
" msr control, r3 \n"/* Restore the CONTROL register value for the task. */
" mov lr, r4 \n"/* LR = r4. */
" ldr r3, xSecureContextConst \n"/* Read the location of xSecureContext i.e. &( xSecureContext ). */
" str r0, [r3] \n"/* Restore the task's xSecureContext. */
" cbz r0, restore_ns_context \n"/* If there is no secure context for the task, restore the non-secure context. */
" ldr r3, pxCurrentTCBConst \n"/* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n"/* Read pxCurrentTCB. */
" push {r2, r4} \n"
" bl SecureContext_LoadContext \n"/* Restore the secure context. Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
" pop {r2, r4} \n"
" mov lr, r4 \n"/* LR = r4. */
" lsls r1, r4, #25 \n"/* r1 = r4 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
" bpl restore_ns_context \n"/* bpl - branch if positive or zero. If r1 >= 0 ==> Bit[6] in EXC_RETURN is 0 i.e. non-secure stack was used. */
" msr psp, r2 \n"/* Remember the new top of stack for the task. */
" bx lr \n"
#else /* configENABLE_MPU */
" ldmia r2!, {r0, r1, r4} \n"/* Read from stack - r0 = xSecureContext, r1 = PSPLIM and r4 = LR. */
" msr psplim, r1 \n"/* Restore the PSPLIM register value for the task. */
" mov lr, r4 \n"/* LR = r4. */
" ldr r3, xSecureContextConst \n"/* Read the location of xSecureContext i.e. &( xSecureContext ). */
" str r0, [r3] \n"/* Restore the task's xSecureContext. */
" cbz r0, restore_ns_context \n"/* If there is no secure context for the task, restore the non-secure context. */
" ldr r3, pxCurrentTCBConst \n"/* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n"/* Read pxCurrentTCB. */
" push {r2, r4} \n"
" bl SecureContext_LoadContext \n"/* Restore the secure context. Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
" pop {r2, r4} \n"
" mov lr, r4 \n"/* LR = r4. */
" lsls r1, r4, #25 \n"/* r1 = r4 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
" bpl restore_ns_context \n"/* bpl - branch if positive or zero. If r1 >= 0 ==> Bit[6] in EXC_RETURN is 0 i.e. non-secure stack was used. */
" msr psp, r2 \n"/* Remember the new top of stack for the task. */
" bx lr \n"
#endif /* configENABLE_MPU */
" ldmia r2!, {r0, r1, r4} \n"/* Read from stack - r0 = xSecureContext, r1 = PSPLIM and r4 = LR. */
" msr psplim, r1 \n"/* Restore the PSPLIM register value for the task. */
" mov lr, r4 \n"/* LR = r4. */
" ldr r3, xSecureContextConst \n"/* Read the location of xSecureContext i.e. &( xSecureContext ). */
" str r0, [r3] \n"/* Restore the task's xSecureContext. */
" cbz r0, restore_ns_context \n"/* If there is no secure context for the task, restore the non-secure context. */
" ldr r3, pxCurrentTCBConst \n"/* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r3] \n"/* Read pxCurrentTCB. */
" push {r2, r4} \n"
" bl SecureContext_LoadContext \n"/* Restore the secure context. Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
" pop {r2, r4} \n"
" mov lr, r4 \n"/* LR = r4. */
" lsls r1, r4, #25 \n"/* r1 = r4 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
" bpl restore_ns_context \n"/* bpl - branch if positive or zero. If r1 >= 0 ==> Bit[6] in EXC_RETURN is 0 i.e. non-secure stack was used. */
" msr psp, r2 \n"/* Remember the new top of stack for the task. */
" bx lr \n"
" \n"
" restore_ns_context: \n"
" ldmia r2!, {r4-r11} \n"/* Restore the registers that are not automatically restored. */
@ -409,17 +506,60 @@ void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
" .align 4 \n"
"pxCurrentTCBConst: .word pxCurrentTCB \n"
"xSecureContextConst: .word xSecureContext \n"
#if ( configENABLE_MPU == 1 )
"xMPUCTRLConst: .word 0xe000ed94 \n"
"xMAIR0Const: .word 0xe000edc0 \n"
"xRNRConst: .word 0xe000ed98 \n"
"xRBARConst: .word 0xe000ed9c \n"
#endif /* configENABLE_MPU */
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
".syntax unified \n"
".extern vPortSVCHandler_C \n"
".extern vSystemCallEnter \n"
".extern vSystemCallEnter_1 \n"
".extern vSystemCallExit \n"
" \n"
"tst lr, #4 \n"
"ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp \n"
" \n"
"ldr r1, [r0, #24] \n"
"ldrb r2, [r1, #-2] \n"
"cmp r2, %0 \n"
"beq syscall_enter \n"
"cmp r2, %1 \n"
"beq syscall_enter_1 \n"
"cmp r2, %2 \n"
"beq syscall_exit \n"
"b vPortSVCHandler_C \n"
" \n"
"syscall_enter: \n"
" mov r1, lr \n"
" b vSystemCallEnter \n"
" \n"
"syscall_enter_1: \n"
" mov r1, lr \n"
" b vSystemCallEnter_1 \n"
" \n"
"syscall_exit: \n"
" mov r1, lr \n"
" b vSystemCallExit \n"
" \n"
: /* No outputs. */
:"i" ( portSVC_SYSTEM_CALL_ENTER ), "i" ( portSVC_SYSTEM_CALL_ENTER_1 ), "i" ( portSVC_SYSTEM_CALL_EXIT )
: "r0", "r1", "r2", "memory"
);
}
#else /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
@ -437,6 +577,8 @@ void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
"svchandler_address_const: .word vPortSVCHandler_C \n"
);
}
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
void vPortAllocateSecureContext( uint32_t ulSecureStackSize ) /* __attribute__ (( naked )) */

View file

@ -186,23 +186,120 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
#define portMPU_REGION_EXECUTE_NEVER ( 1UL )
/*-----------------------------------------------------------*/
/**
* @brief Settings to define an MPU region.
*/
typedef struct MPURegionSettings
{
uint32_t ulRBAR; /**< RBAR for the region. */
uint32_t ulRLAR; /**< RLAR for the region. */
} MPURegionSettings_t;
#if ( configENABLE_MPU == 1 )
/**
* @brief MPU settings as stored in the TCB.
*/
typedef struct MPU_SETTINGS
{
uint32_t ulMAIR0; /**< MAIR0 for the task containing attributes for all the 4 per task regions. */
MPURegionSettings_t xRegionsSettings[ portTOTAL_NUM_REGIONS ]; /**< Settings for 4 per task regions. */
} xMPU_SETTINGS;
/**
* @brief Settings to define an MPU region.
*/
typedef struct MPURegionSettings
{
uint32_t ulRBAR; /**< RBAR for the region. */
uint32_t ulRLAR; /**< RLAR for the region. */
} MPURegionSettings_t;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
#ifndef configSYSTEM_CALL_STACK_SIZE
#error configSYSTEM_CALL_STACK_SIZE must be defined to the desired size of the system call stack in words for using MPU wrappers v2.
#endif
/**
* @brief System call stack.
*/
typedef struct SYSTEM_CALL_STACK_INFO
{
uint32_t ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE ];
uint32_t * pulSystemCallStack;
uint32_t * pulSystemCallStackLimit;
uint32_t * pulTaskStack;
uint32_t ulLinkRegisterAtSystemCallEntry;
uint32_t ulStackLimitRegisterAtSystemCallEntry;
} xSYSTEM_CALL_STACK_INFO;
#endif /* configUSE_MPU_WRAPPERS_V1 == 0 */
/**
* @brief MPU settings as stored in the TCB.
*/
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
#if( configENABLE_TRUSTZONE == 1 )
/*
* +-----------+---------------+----------+-----------------+------------------------------+-----+
* | s16-s31 | s0-s15, FPSCR | r4-r11 | r0-r3, r12, LR, | xSecureContext, PSP, PSPLIM, | |
* | | | | PC, xPSR | CONTROL, EXC_RETURN | |
* +-----------+---------------+----------+-----------------+------------------------------+-----+
*
* <-----------><--------------><---------><----------------><-----------------------------><---->
* 16 16 8 8 5 1
*/
#define MAX_CONTEXT_SIZE 54
#else /* #if( configENABLE_TRUSTZONE == 1 ) */
/*
* +-----------+---------------+----------+-----------------+----------------------+-----+
* | s16-s31 | s0-s15, FPSCR | r4-r11 | r0-r3, r12, LR, | PSP, PSPLIM, CONTROL | |
* | | | | PC, xPSR | EXC_RETURN | |
* +-----------+---------------+----------+-----------------+----------------------+-----+
*
* <-----------><--------------><---------><----------------><---------------------><---->
* 16 16 8 8 4 1
*/
#define MAX_CONTEXT_SIZE 53
#endif /* #if( configENABLE_TRUSTZONE == 1 ) */
#else /* #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */
#if( configENABLE_TRUSTZONE == 1 )
/*
* +----------+-----------------+------------------------------+-----+
* | r4-r11 | r0-r3, r12, LR, | xSecureContext, PSP, PSPLIM, | |
* | | PC, xPSR | CONTROL, EXC_RETURN | |
* +----------+-----------------+------------------------------+-----+
*
* <---------><----------------><------------------------------><---->
* 8 8 5 1
*/
#define MAX_CONTEXT_SIZE 22
#else /* #if( configENABLE_TRUSTZONE == 1 ) */
/*
* +----------+-----------------+----------------------+-----+
* | r4-r11 | r0-r3, r12, LR, | PSP, PSPLIM, CONTROL | |
* | | PC, xPSR | EXC_RETURN | |
* +----------+-----------------+----------------------+-----+
*
* <---------><----------------><----------------------><---->
* 8 8 4 1
*/
#define MAX_CONTEXT_SIZE 21
#endif /* #if( configENABLE_TRUSTZONE == 1 ) */
#endif /* #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */
/* Flags used for xMPU_SETTINGS.ulTaskFlags member. */
#define portSTACK_FRAME_HAS_PADDING_FLAG ( 1UL << 0UL )
#define portTASK_IS_PRIVILEGED_FLAG ( 1UL << 1UL )
typedef struct MPU_SETTINGS
{
uint32_t ulMAIR0; /**< MAIR0 for the task containing attributes for all the 4 per task regions. */
MPURegionSettings_t xRegionsSettings[ portTOTAL_NUM_REGIONS ]; /**< Settings for 4 per task regions. */
uint32_t ulContext[ MAX_CONTEXT_SIZE ];
uint32_t ulTaskFlags;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
xSYSTEM_CALL_STACK_INFO xSystemCallStackInfo;
#endif
} xMPU_SETTINGS;
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
/**
@ -223,6 +320,9 @@ typedef struct MPU_SETTINGS
#define portSVC_FREE_SECURE_CONTEXT 1
#define portSVC_START_SCHEDULER 2
#define portSVC_RAISE_PRIVILEGE 3
#define portSVC_SYSTEM_CALL_ENTER 4 /* System calls with upto 4 parameters. */
#define portSVC_SYSTEM_CALL_ENTER_1 5 /* System calls with 5 parameters. */
#define portSVC_SYSTEM_CALL_EXIT 6
/*-----------------------------------------------------------*/
/**
@ -315,6 +415,20 @@ typedef struct MPU_SETTINGS
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
extern BaseType_t xPortIsTaskPrivileged( void );
/**
* @brief Checks whether or not the calling task is privileged.
*
* @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
*/
#define portIS_TASK_PRIVILEGED() xPortIsTaskPrivileged()
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
/**
* @brief Barriers.
*/