2 * FreeRTOS Kernel V10.5.1
\r
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * SPDX-License-Identifier: MIT
\r
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
8 * this software and associated documentation files (the "Software"), to deal in
\r
9 * the Software without restriction, including without limitation the rights to
\r
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
11 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
12 * subject to the following conditions:
\r
14 * The above copyright notice and this permission notice shall be included in all
\r
15 * copies or substantial portions of the Software.
\r
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
24 * https://www.FreeRTOS.org
\r
25 * https://github.com/FreeRTOS
\r
29 /* Secure context includes. */
\r
30 #include "secure_context.h"
\r
32 /* Secure heap includes. */
\r
33 #include "secure_heap.h"
\r
35 /* Secure port macros. */
\r
36 #include "secure_port_macros.h"
\r
39 * @brief CONTROL value for privileged tasks.
\r
41 * Bit[0] - 0 --> Thread mode is privileged.
\r
42 * Bit[1] - 1 --> Thread mode uses PSP.
\r
44 #define securecontextCONTROL_VALUE_PRIVILEGED 0x02
\r
47 * @brief CONTROL value for un-privileged tasks.
\r
49 * Bit[0] - 1 --> Thread mode is un-privileged.
\r
50 * Bit[1] - 1 --> Thread mode uses PSP.
\r
52 #define securecontextCONTROL_VALUE_UNPRIVILEGED 0x03
\r
55 * @brief Size of stack seal values in bytes.
\r
57 #define securecontextSTACK_SEAL_SIZE 8
\r
60 * @brief Stack seal value as recommended by ARM.
\r
62 #define securecontextSTACK_SEAL_VALUE 0xFEF5EDA5
\r
65 * @brief Maximum number of secure contexts.
\r
67 #ifndef secureconfigMAX_SECURE_CONTEXTS
\r
68 #define secureconfigMAX_SECURE_CONTEXTS 8UL
\r
70 /*-----------------------------------------------------------*/
\r
73 * @brief Pre-allocated array of secure contexts.
\r
75 SecureContext_t xSecureContexts[ secureconfigMAX_SECURE_CONTEXTS ];
\r
76 /*-----------------------------------------------------------*/
\r
79 * @brief Get a free secure context for a task from the secure context pool (xSecureContexts).
\r
81 * This function ensures that only one secure context is allocated for a task.
\r
83 * @param[in] pvTaskHandle The task handle for which the secure context is allocated.
\r
85 * @return Index of a free secure context in the xSecureContexts array.
\r
87 static uint32_t ulGetSecureContext( void * pvTaskHandle );
\r
90 * @brief Return the secure context to the secure context pool (xSecureContexts).
\r
92 * @param[in] ulSecureContextIndex Index of the context in the xSecureContexts array.
\r
94 static void vReturnSecureContext( uint32_t ulSecureContextIndex );
\r
96 /* These are implemented in assembly. */
\r
97 extern void SecureContext_LoadContextAsm( SecureContext_t * pxSecureContext );
\r
98 extern void SecureContext_SaveContextAsm( SecureContext_t * pxSecureContext );
\r
99 /*-----------------------------------------------------------*/
\r
101 static uint32_t ulGetSecureContext( void * pvTaskHandle )
\r
103 /* Start with invalid index. */
\r
104 uint32_t i, ulSecureContextIndex = secureconfigMAX_SECURE_CONTEXTS;
\r
106 for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )
\r
108 if( ( xSecureContexts[ i ].pucCurrentStackPointer == NULL ) &&
\r
109 ( xSecureContexts[ i ].pucStackLimit == NULL ) &&
\r
110 ( xSecureContexts[ i ].pucStackStart == NULL ) &&
\r
111 ( xSecureContexts[ i ].pvTaskHandle == NULL ) &&
\r
112 ( ulSecureContextIndex == secureconfigMAX_SECURE_CONTEXTS ) )
\r
114 ulSecureContextIndex = i;
\r
116 else if( xSecureContexts[ i ].pvTaskHandle == pvTaskHandle )
\r
118 /* A task can only have one secure context. Do not allocate a second
\r
119 * context for the same task. */
\r
120 ulSecureContextIndex = secureconfigMAX_SECURE_CONTEXTS;
\r
125 return ulSecureContextIndex;
\r
127 /*-----------------------------------------------------------*/
\r
129 static void vReturnSecureContext( uint32_t ulSecureContextIndex )
\r
131 xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = NULL;
\r
132 xSecureContexts[ ulSecureContextIndex ].pucStackLimit = NULL;
\r
133 xSecureContexts[ ulSecureContextIndex ].pucStackStart = NULL;
\r
134 xSecureContexts[ ulSecureContextIndex ].pvTaskHandle = NULL;
\r
136 /*-----------------------------------------------------------*/
\r
138 secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
\r
140 uint32_t ulIPSR, i;
\r
141 static uint32_t ulSecureContextsInitialized = 0;
\r
143 /* Read the Interrupt Program Status Register (IPSR) value. */
\r
144 secureportREAD_IPSR( ulIPSR );
\r
146 /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
\r
147 * when the processor is running in the Thread Mode. */
\r
148 if( ( ulIPSR != 0 ) && ( ulSecureContextsInitialized == 0 ) )
\r
150 /* Ensure to initialize secure contexts only once. */
\r
151 ulSecureContextsInitialized = 1;
\r
153 /* No stack for thread mode until a task's context is loaded. */
\r
154 secureportSET_PSPLIM( securecontextNO_STACK );
\r
155 secureportSET_PSP( securecontextNO_STACK );
\r
157 /* Initialize all secure contexts. */
\r
158 for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )
\r
160 xSecureContexts[ i ].pucCurrentStackPointer = NULL;
\r
161 xSecureContexts[ i ].pucStackLimit = NULL;
\r
162 xSecureContexts[ i ].pucStackStart = NULL;
\r
163 xSecureContexts[ i ].pvTaskHandle = NULL;
\r
166 #if ( configENABLE_MPU == 1 )
\r
168 /* Configure thread mode to use PSP and to be unprivileged. */
\r
169 secureportSET_CONTROL( securecontextCONTROL_VALUE_UNPRIVILEGED );
\r
171 #else /* configENABLE_MPU */
\r
173 /* Configure thread mode to use PSP and to be privileged. */
\r
174 secureportSET_CONTROL( securecontextCONTROL_VALUE_PRIVILEGED );
\r
176 #endif /* configENABLE_MPU */
\r
179 /*-----------------------------------------------------------*/
\r
181 #if ( configENABLE_MPU == 1 )
\r
182 secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
\r
183 uint32_t ulIsTaskPrivileged,
\r
184 void * pvTaskHandle )
\r
185 #else /* configENABLE_MPU */
\r
186 secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
\r
187 void * pvTaskHandle )
\r
188 #endif /* configENABLE_MPU */
\r
190 uint8_t * pucStackMemory = NULL;
\r
191 uint8_t * pucStackLimit;
\r
192 uint32_t ulIPSR, ulSecureContextIndex;
\r
193 SecureContextHandle_t xSecureContextHandle = securecontextINVALID_CONTEXT_ID;
\r
195 #if ( configENABLE_MPU == 1 )
\r
196 uint32_t * pulCurrentStackPointer = NULL;
\r
197 #endif /* configENABLE_MPU */
\r
199 /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit
\r
200 * Register (PSPLIM) value. */
\r
201 secureportREAD_IPSR( ulIPSR );
\r
202 secureportREAD_PSPLIM( pucStackLimit );
\r
204 /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
\r
205 * when the processor is running in the Thread Mode.
\r
206 * Also do nothing, if a secure context us already loaded. PSPLIM is set to
\r
207 * securecontextNO_STACK when no secure context is loaded. */
\r
208 if( ( ulIPSR != 0 ) && ( pucStackLimit == securecontextNO_STACK ) )
\r
210 /* Ontain a free secure context. */
\r
211 ulSecureContextIndex = ulGetSecureContext( pvTaskHandle );
\r
213 /* Were we able to get a free context? */
\r
214 if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS )
\r
216 /* Allocate the stack space. */
\r
217 pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE );
\r
219 if( pucStackMemory != NULL )
\r
221 /* Since stack grows down, the starting point will be the last
\r
222 * location. Note that this location is next to the last
\r
223 * allocated byte for stack (excluding the space for seal values)
\r
224 * because the hardware decrements the stack pointer before
\r
225 * writing i.e. if stack pointer is 0x2, a push operation will
\r
226 * decrement the stack pointer to 0x1 and then write at 0x1. */
\r
227 xSecureContexts[ ulSecureContextIndex ].pucStackStart = pucStackMemory + ulSecureStackSize;
\r
229 /* Seal the created secure process stack. */
\r
230 *( uint32_t * )( pucStackMemory + ulSecureStackSize ) = securecontextSTACK_SEAL_VALUE;
\r
231 *( uint32_t * )( pucStackMemory + ulSecureStackSize + 4 ) = securecontextSTACK_SEAL_VALUE;
\r
233 /* The stack cannot go beyond this location. This value is
\r
234 * programmed in the PSPLIM register on context switch.*/
\r
235 xSecureContexts[ ulSecureContextIndex ].pucStackLimit = pucStackMemory;
\r
237 xSecureContexts[ ulSecureContextIndex ].pvTaskHandle = pvTaskHandle;
\r
239 #if ( configENABLE_MPU == 1 )
\r
241 /* Store the correct CONTROL value for the task on the stack.
\r
242 * This value is programmed in the CONTROL register on
\r
243 * context switch. */
\r
244 pulCurrentStackPointer = ( uint32_t * ) xSecureContexts[ ulSecureContextIndex ].pucStackStart;
\r
245 pulCurrentStackPointer--;
\r
247 if( ulIsTaskPrivileged )
\r
249 *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;
\r
253 *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_UNPRIVILEGED;
\r
256 /* Store the current stack pointer. This value is programmed in
\r
257 * the PSP register on context switch. */
\r
258 xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = ( uint8_t * ) pulCurrentStackPointer;
\r
260 #else /* configENABLE_MPU */
\r
262 /* Current SP is set to the starting of the stack. This
\r
263 * value programmed in the PSP register on context switch. */
\r
264 xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = xSecureContexts[ ulSecureContextIndex ].pucStackStart;
\r
266 #endif /* configENABLE_MPU */
\r
268 /* Ensure to never return 0 as a valid context handle. */
\r
269 xSecureContextHandle = ulSecureContextIndex + 1UL;
\r
274 return xSecureContextHandle;
\r
276 /*-----------------------------------------------------------*/
\r
278 secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )
\r
280 uint32_t ulIPSR, ulSecureContextIndex;
\r
282 /* Read the Interrupt Program Status Register (IPSR) value. */
\r
283 secureportREAD_IPSR( ulIPSR );
\r
285 /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
\r
286 * when the processor is running in the Thread Mode. */
\r
289 /* Only free if a valid context handle is passed. */
\r
290 if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
\r
292 ulSecureContextIndex = xSecureContextHandle - 1UL;
\r
294 /* Ensure that the secure context being deleted is associated with
\r
296 if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle )
\r
298 /* Free the stack space. */
\r
299 vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit );
\r
301 /* Return the secure context back to the free secure contexts pool. */
\r
302 vReturnSecureContext( ulSecureContextIndex );
\r
307 /*-----------------------------------------------------------*/
\r
309 secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )
\r
311 uint8_t * pucStackLimit;
\r
312 uint32_t ulSecureContextIndex;
\r
314 if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
\r
316 ulSecureContextIndex = xSecureContextHandle - 1UL;
\r
318 secureportREAD_PSPLIM( pucStackLimit );
\r
320 /* Ensure that no secure context is loaded and the task is loading it's
\r
322 if( ( pucStackLimit == securecontextNO_STACK ) &&
\r
323 ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
\r
325 SecureContext_LoadContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
\r
329 /*-----------------------------------------------------------*/
\r
331 secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )
\r
333 uint8_t * pucStackLimit;
\r
334 uint32_t ulSecureContextIndex;
\r
336 if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
\r
338 ulSecureContextIndex = xSecureContextHandle - 1UL;
\r
340 secureportREAD_PSPLIM( pucStackLimit );
\r
342 /* Ensure that task's context is loaded and the task is saving it's own
\r
344 if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) &&
\r
345 ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
\r
347 SecureContext_SaveContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
\r
351 /*-----------------------------------------------------------*/
\r