Pre-allocate secure-side context structures

This commit improves ARMv8-M security by pre-allocating secure-side task
context structures and changing how tasks reference a secure-side
context structure when calling a secure function. The new configuration
constant secureconfigMAX_SECURE_CONTEXTS sets the number of secure
context structures to pre-allocate. secureconfigMAX_SECURE_CONTEXTS
defaults to 8 if left undefined.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
This commit is contained in:
Gaurav Aggarwal 2021-08-04 14:52:22 -07:00 committed by Gaurav-Aggarwal-AWS
parent f8ada39d85
commit ccaa0f4d6e
27 changed files with 1012 additions and 657 deletions

View file

@ -50,25 +50,74 @@
* Bit[1] - 1 --> Thread mode uses PSP.
*/
#define securecontextCONTROL_VALUE_UNPRIVILEGED 0x03
/**
* @brief Invalid context ID.
*/
#define securecontextINVALID_CONTEXT_ID 0UL
/**
* @brief Maximum number of secure contexts.
*/
#ifndef secureconfigMAX_SECURE_CONTEXTS
#define secureconfigMAX_SECURE_CONTEXTS 8UL
#endif
/*-----------------------------------------------------------*/
/**
* @brief Structure to represent secure context.
*
* @note Since stack grows down, pucStackStart is the highest address while
* pucStackLimit is the first addess of the allocated memory.
* @brief Pre-allocated array of secure contexts.
*/
typedef struct SecureContext
SecureContext_t xSecureContexts[ secureconfigMAX_SECURE_CONTEXTS ];
/*-----------------------------------------------------------*/
/**
* @brief Get a free context from the secure context pool (xSecureContexts).
*
* @return Index of a free context in the xSecureContexts array.
*/
static uint32_t ulGetSecureContext( void );
/**
* @brief Return the secure context to the secure context pool (xSecureContexts).
*
* @param[in] ulSecureContextIndex Index of the context in the xSecureContexts array.
*/
static void vReturnSecureContext( uint32_t ulSecureContextIndex );
/* These are implemented in assembly. */
extern void SecureContext_LoadContextAsm( SecureContext_t * pxSecureContext );
extern void SecureContext_SaveContextAsm( SecureContext_t * pxSecureContext );
/*-----------------------------------------------------------*/
static uint32_t ulGetSecureContext( void )
{
uint8_t * pucCurrentStackPointer; /**< Current value of stack pointer (PSP). */
uint8_t * pucStackLimit; /**< Last location of the stack memory (PSPLIM). */
uint8_t * pucStackStart; /**< First location of the stack memory. */
} SecureContext_t;
uint32_t ulSecureContextIndex;
for( ulSecureContextIndex = 0; ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS; ulSecureContextIndex++ )
{
if( ( xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer == NULL ) &&
( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == NULL ) &&
( xSecureContexts[ ulSecureContextIndex ].pucStackStart == NULL ) )
{
break;
}
}
return ulSecureContextIndex;
}
/*-----------------------------------------------------------*/
static void vReturnSecureContext( uint32_t ulSecureContextIndex )
{
xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = NULL;
xSecureContexts[ ulSecureContextIndex ].pucStackLimit = NULL;
xSecureContexts[ ulSecureContextIndex ].pucStackStart = NULL;
}
/*-----------------------------------------------------------*/
secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
{
uint32_t ulIPSR;
uint32_t ulIPSR, i;
/* Read the Interrupt Program Status Register (IPSR) value. */
secureportREAD_IPSR( ulIPSR );
@ -81,6 +130,14 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
secureportSET_PSPLIM( securecontextNO_STACK );
secureportSET_PSP( securecontextNO_STACK );
/* Initialize all secure contexts. */
for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )
{
xSecureContexts[ i ].pucCurrentStackPointer = NULL;
xSecureContexts[ i ].pucStackLimit = NULL;
xSecureContexts[ i ].pucStackStart = NULL;
}
#if ( configENABLE_MPU == 1 )
{
/* Configure thread mode to use PSP and to be unprivileged. */
@ -88,7 +145,7 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
}
#else /* configENABLE_MPU */
{
/* Configure thread mode to use PSP and to be privileged.. */
/* Configure thread mode to use PSP and to be privileged. */
secureportSET_CONTROL( securecontextCONTROL_VALUE_PRIVILEGED );
}
#endif /* configENABLE_MPU */
@ -104,8 +161,8 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
#endif /* configENABLE_MPU */
{
uint8_t * pucStackMemory = NULL;
uint32_t ulIPSR;
SecureContextHandle_t xSecureContextHandle = NULL;
uint32_t ulIPSR, ulSecureContextIndex;
SecureContextHandle_t xSecureContextHandle;
#if ( configENABLE_MPU == 1 )
uint32_t * pulCurrentStackPointer = NULL;
@ -118,10 +175,11 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
* when the processor is running in the Thread Mode. */
if( ulIPSR != 0 )
{
/* Allocate the context structure. */
xSecureContextHandle = ( SecureContextHandle_t ) pvPortMalloc( sizeof( SecureContext_t ) );
/* Ontain a free secure context. */
ulSecureContextIndex = ulGetSecureContext();
if( xSecureContextHandle != NULL )
/* Were we able to get a free context? */
if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS )
{
/* Allocate the stack space. */
pucStackMemory = pvPortMalloc( ulSecureStackSize );
@ -134,18 +192,18 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
* pointer before writing i.e. if stack pointer is 0x2, a push
* operation will decrement the stack pointer to 0x1 and then
* write at 0x1. */
xSecureContextHandle->pucStackStart = pucStackMemory + ulSecureStackSize;
xSecureContexts[ ulSecureContextIndex ].pucStackStart = pucStackMemory + ulSecureStackSize;
/* The stack cannot go beyond this location. This value is
* programmed in the PSPLIM register on context switch.*/
xSecureContextHandle->pucStackLimit = pucStackMemory;
xSecureContexts[ ulSecureContextIndex ].pucStackLimit = pucStackMemory;
#if ( configENABLE_MPU == 1 )
{
/* Store the correct CONTROL value for the task on the stack.
* This value is programmed in the CONTROL register on
* context switch. */
pulCurrentStackPointer = ( uint32_t * ) xSecureContextHandle->pucStackStart;
pulCurrentStackPointer = ( uint32_t * ) xSecureContexts[ ulSecureContextIndex ].pucStackStart;
pulCurrentStackPointer--;
if( ulIsTaskPrivileged )
@ -159,22 +217,22 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
/* Store the current stack pointer. This value is programmed in
* the PSP register on context switch. */
xSecureContextHandle->pucCurrentStackPointer = ( uint8_t * ) pulCurrentStackPointer;
xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = ( uint8_t * ) pulCurrentStackPointer;
}
#else /* configENABLE_MPU */
{
/* Current SP is set to the starting of the stack. This
* value programmed in the PSP register on context switch. */
xSecureContextHandle->pucCurrentStackPointer = xSecureContextHandle->pucStackStart;
xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = xSecureContexts[ ulSecureContextIndex ].pucStackStart;
}
#endif /* configENABLE_MPU */
/* Ensure to never return 0 as a valid context handle. */
xSecureContextHandle = ulSecureContextIndex + 1UL;
}
else
{
/* Free the context to avoid memory leak and make sure to return
* NULL to indicate failure. */
vPortFree( xSecureContextHandle );
xSecureContextHandle = NULL;
xSecureContextHandle = securecontextINVALID_CONTEXT_ID;
}
}
}
@ -185,7 +243,7 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle )
{
uint32_t ulIPSR;
uint32_t ulIPSR, ulSecureContextIndex;
/* Read the Interrupt Program Status Register (IPSR) value. */
secureportREAD_IPSR( ulIPSR );
@ -194,14 +252,43 @@ secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandl
* when the processor is running in the Thread Mode. */
if( ulIPSR != 0 )
{
/* Ensure that valid parameters are passed. */
secureportASSERT( xSecureContextHandle != NULL );
/* Only free if a valid context handle is passed. */
if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
{
ulSecureContextIndex = xSecureContextHandle - 1UL;
/* Free the stack space. */
vPortFree( xSecureContextHandle->pucStackLimit );
/* Free the stack space. */
vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit );
/* Free the context itself. */
vPortFree( xSecureContextHandle );
/* Return the context back to the free contexts pool. */
vReturnSecureContext( ulSecureContextIndex );
}
}
}
/*-----------------------------------------------------------*/
secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle )
{
uint32_t ulSecureContextIndex;
if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
{
ulSecureContextIndex = xSecureContextHandle - 1UL;
SecureContext_LoadContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
}
}
/*-----------------------------------------------------------*/
secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle )
{
uint32_t ulSecureContextIndex;
if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
{
ulSecureContextIndex = xSecureContextHandle - 1UL;
SecureContext_SaveContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
}
}
/*-----------------------------------------------------------*/

View file

@ -36,15 +36,29 @@
#include "FreeRTOSConfig.h"
/**
* @brief PSP value when no task's context is loaded.
* @brief PSP value when no secure context is loaded.
*/
#define securecontextNO_STACK 0x0
/*-----------------------------------------------------------*/
/**
* @brief Opaque handle.
* @brief Structure to represent a secure context.
*
* @note Since stack grows down, pucStackStart is the highest address while
* pucStackLimit is the first address of the allocated memory.
*/
struct SecureContext;
typedef struct SecureContext * SecureContextHandle_t;
typedef struct SecureContext
{
uint8_t * pucCurrentStackPointer; /**< Current value of stack pointer (PSP). */
uint8_t * pucStackLimit; /**< Last location of the stack memory (PSPLIM). */
uint8_t * pucStackStart; /**< First location of the stack memory. */
} SecureContext_t;
/*-----------------------------------------------------------*/
/**
* @brief Opaque handle for a secure context.
*/
typedef uint32_t SecureContextHandle_t;
/*-----------------------------------------------------------*/
/**

View file

@ -32,57 +32,62 @@
/* Secure port macros. */
#include "secure_port_macros.h"
secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle )
void SecureContext_LoadContextAsm( SecureContext_t * pxSecureContext )
{
/* xSecureContextHandle value is in r0. */
/* pxSecureContext value is in r0. */
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r1, ipsr \n"/* r1 = IPSR. */
" cbz r1, load_ctx_therad_mode \n"/* Do nothing if the processor is running in the Thread Mode. */
" ldmia r0!, {r1, r2} \n"/* r1 = xSecureContextHandle->pucCurrentStackPointer, r2 = xSecureContextHandle->pucStackLimit. */
" .syntax unified \n"
" \n"
" mrs r1, ipsr \n" /* r1 = IPSR. */
" cbz r1, load_ctx_therad_mode \n" /* Do nothing if the processor is running in the Thread Mode. */
" ldmia r0!, {r1, r2} \n" /* r1 = pxSecureContext->pucCurrentStackPointer, r2 = pxSecureContext->pucStackLimit. */
" \n"
#if ( configENABLE_MPU == 1 )
" ldmia r1!, {r3} \n"/* Read CONTROL register value from task's stack. r3 = CONTROL. */
" msr control, r3 \n"/* CONTROL = r3. */
" ldmia r1!, {r3} \n" /* Read CONTROL register value from task's stack. r3 = CONTROL. */
" msr control, r3 \n" /* CONTROL = r3. */
#endif /* configENABLE_MPU */
" msr psplim, r2 \n"/* PSPLIM = r2. */
" msr psp, r1 \n"/* PSP = r1. */
" \n"
" load_ctx_therad_mode: \n"
" nop \n"
" \n"
" \n"
" msr psplim, r2 \n" /* PSPLIM = r2. */
" msr psp, r1 \n" /* PSP = r1. */
" \n"
" load_ctx_therad_mode: \n"
" bx lr \n"
" \n"
::: "r0", "r1", "r2"
);
}
/*-----------------------------------------------------------*/
secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle )
void SecureContext_SaveContextAsm( SecureContext_t * pxSecureContext )
{
/* xSecureContextHandle value is in r0. */
/* pxSecureContext value is in r0. */
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r1, ipsr \n"/* r1 = IPSR. */
" cbz r1, save_ctx_therad_mode \n"/* Do nothing if the processor is running in the Thread Mode. */
" mrs r1, psp \n"/* r1 = PSP. */
" .syntax unified \n"
" \n"
" mrs r1, ipsr \n" /* r1 = IPSR. */
" cbz r1, save_ctx_therad_mode \n" /* Do nothing if the processor is running in the Thread Mode. */
" mrs r1, psp \n" /* r1 = PSP. */
" \n"
#if ( configENABLE_FPU == 1 )
" vstmdb r1!, {s0} \n"/* Trigger the defferred stacking of FPU registers. */
" vldmia r1!, {s0} \n"/* Nullify the effect of the pervious statement. */
" vstmdb r1!, {s0} \n" /* Trigger the defferred stacking of FPU registers. */
" vldmia r1!, {s0} \n" /* Nullify the effect of the pervious statement. */
#endif /* configENABLE_FPU */
" \n"
#if ( configENABLE_MPU == 1 )
" mrs r2, control \n"/* r2 = CONTROL. */
" stmdb r1!, {r2} \n"/* Store CONTROL value on the stack. */
" mrs r2, control \n" /* r2 = CONTROL. */
" stmdb r1!, {r2} \n" /* Store CONTROL value on the stack. */
#endif /* configENABLE_MPU */
" str r1, [r0] \n"/* Save the top of stack in context. xSecureContextHandle->pucCurrentStackPointer = r1. */
" movs r1, %0 \n"/* r1 = securecontextNO_STACK. */
" msr psplim, r1 \n"/* PSPLIM = securecontextNO_STACK. */
" msr psp, r1 \n"/* PSP = securecontextNO_STACK i.e. No stack for thread mode until next task's context is loaded. */
" \n"
" save_ctx_therad_mode: \n"
" nop \n"
" \n"
" \n"
" str r1, [r0] \n" /* Save the top of stack in context. pxSecureContext->pucCurrentStackPointer = r1. */
" movs r1, %0 \n" /* r1 = securecontextNO_STACK. */
" msr psplim, r1 \n" /* PSPLIM = securecontextNO_STACK. */
" msr psp, r1 \n" /* PSP = securecontextNO_STACK i.e. No stack for thread mode until next task's context is loaded. */
" \n"
" save_ctx_therad_mode: \n"
" bx lr \n"
" \n"
::"i" ( securecontextNO_STACK ) : "r1", "memory"
);
}

View file

@ -38,7 +38,9 @@
/**
* @brief Total heap size.
*/
#define secureconfigTOTAL_HEAP_SIZE ( ( ( size_t ) ( 10 * 1024 ) ) )
#ifndef secureconfigTOTAL_HEAP_SIZE
#define secureconfigTOTAL_HEAP_SIZE ( ( ( size_t ) ( 10 * 1024 ) ) )
#endif
/* No test marker by default. */
#ifndef mtCOVERAGE_TEST_MARKER