]> begriffs open source - freertos/blob - portable/GCC/ARM_CM33/secure/secure_context.c
[AUTO][RELEASE]: Bump file header version to "11.1.0"
[freertos] / portable / GCC / ARM_CM33 / secure / secure_context.c
1 /*
2  * FreeRTOS Kernel V11.1.0
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /* Secure context includes. */
30 #include "secure_context.h"
31
32 /* Secure heap includes. */
33 #include "secure_heap.h"
34
35 /* Secure port macros. */
36 #include "secure_port_macros.h"
37
38 /**
39  * @brief CONTROL value for privileged tasks.
40  *
41  * Bit[0] - 0 --> Thread mode is privileged.
42  * Bit[1] - 1 --> Thread mode uses PSP.
43  */
44 #define securecontextCONTROL_VALUE_PRIVILEGED      0x02
45
46 /**
47  * @brief CONTROL value for un-privileged tasks.
48  *
49  * Bit[0] - 1 --> Thread mode is un-privileged.
50  * Bit[1] - 1 --> Thread mode uses PSP.
51  */
52 #define securecontextCONTROL_VALUE_UNPRIVILEGED    0x03
53
54 /**
55  * @brief Size of stack seal values in bytes.
56  */
57 #define securecontextSTACK_SEAL_SIZE               8
58
59 /**
60  * @brief Stack seal value as recommended by ARM.
61  */
62 #define securecontextSTACK_SEAL_VALUE              0xFEF5EDA5
63
64 /**
65  * @brief Maximum number of secure contexts.
66  */
67 #ifndef secureconfigMAX_SECURE_CONTEXTS
68     #define secureconfigMAX_SECURE_CONTEXTS    8UL
69 #endif
70 /*-----------------------------------------------------------*/
71
72 /**
73  * @brief Pre-allocated array of secure contexts.
74  */
75 SecureContext_t xSecureContexts[ secureconfigMAX_SECURE_CONTEXTS ];
76 /*-----------------------------------------------------------*/
77
78 /**
79  * @brief Get a free secure context for a task from the secure context pool (xSecureContexts).
80  *
81  * This function ensures that only one secure context is allocated for a task.
82  *
83  * @param[in] pvTaskHandle The task handle for which the secure context is allocated.
84  *
85  * @return Index of a free secure context in the xSecureContexts array.
86  */
87 static uint32_t ulGetSecureContext( void * pvTaskHandle );
88
89 /**
90  * @brief Return the secure context to the secure context pool (xSecureContexts).
91  *
92  * @param[in] ulSecureContextIndex Index of the context in the xSecureContexts array.
93  */
94 static void vReturnSecureContext( uint32_t ulSecureContextIndex );
95
96 /* These are implemented in assembly. */
97 extern void SecureContext_LoadContextAsm( SecureContext_t * pxSecureContext );
98 extern void SecureContext_SaveContextAsm( SecureContext_t * pxSecureContext );
99 /*-----------------------------------------------------------*/
100
101 static uint32_t ulGetSecureContext( void * pvTaskHandle )
102 {
103     /* Start with invalid index. */
104     uint32_t i, ulSecureContextIndex = secureconfigMAX_SECURE_CONTEXTS;
105
106     for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )
107     {
108         if( ( xSecureContexts[ i ].pucCurrentStackPointer == NULL ) &&
109             ( xSecureContexts[ i ].pucStackLimit == NULL ) &&
110             ( xSecureContexts[ i ].pucStackStart == NULL ) &&
111             ( xSecureContexts[ i ].pvTaskHandle == NULL ) &&
112             ( ulSecureContextIndex == secureconfigMAX_SECURE_CONTEXTS ) )
113         {
114             ulSecureContextIndex = i;
115         }
116         else if( xSecureContexts[ i ].pvTaskHandle == pvTaskHandle )
117         {
118             /* A task can only have one secure context. Do not allocate a second
119              * context for the same task. */
120             ulSecureContextIndex = secureconfigMAX_SECURE_CONTEXTS;
121             break;
122         }
123     }
124
125     return ulSecureContextIndex;
126 }
127 /*-----------------------------------------------------------*/
128
129 static void vReturnSecureContext( uint32_t ulSecureContextIndex )
130 {
131     xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = NULL;
132     xSecureContexts[ ulSecureContextIndex ].pucStackLimit = NULL;
133     xSecureContexts[ ulSecureContextIndex ].pucStackStart = NULL;
134     xSecureContexts[ ulSecureContextIndex ].pvTaskHandle = NULL;
135 }
136 /*-----------------------------------------------------------*/
137
138 secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
139 {
140     uint32_t ulIPSR, i;
141     static uint32_t ulSecureContextsInitialized = 0;
142
143     /* Read the Interrupt Program Status Register (IPSR) value. */
144     secureportREAD_IPSR( ulIPSR );
145
146     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
147      * when the processor is running in the Thread Mode. */
148     if( ( ulIPSR != 0 ) && ( ulSecureContextsInitialized == 0 ) )
149     {
150         /* Ensure to initialize secure contexts only once. */
151         ulSecureContextsInitialized = 1;
152
153         /* No stack for thread mode until a task's context is loaded. */
154         secureportSET_PSPLIM( securecontextNO_STACK );
155         secureportSET_PSP( securecontextNO_STACK );
156
157         /* Initialize all secure contexts. */
158         for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )
159         {
160             xSecureContexts[ i ].pucCurrentStackPointer = NULL;
161             xSecureContexts[ i ].pucStackLimit = NULL;
162             xSecureContexts[ i ].pucStackStart = NULL;
163             xSecureContexts[ i ].pvTaskHandle = NULL;
164         }
165
166         #if ( configENABLE_MPU == 1 )
167         {
168             /* Configure thread mode to use PSP and to be unprivileged. */
169             secureportSET_CONTROL( securecontextCONTROL_VALUE_UNPRIVILEGED );
170         }
171         #else /* configENABLE_MPU */
172         {
173             /* Configure thread mode to use PSP and to be privileged. */
174             secureportSET_CONTROL( securecontextCONTROL_VALUE_PRIVILEGED );
175         }
176         #endif /* configENABLE_MPU */
177     }
178 }
179 /*-----------------------------------------------------------*/
180
181 #if ( configENABLE_MPU == 1 )
182     secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
183                                                                                        uint32_t ulIsTaskPrivileged,
184                                                                                        void * pvTaskHandle )
185 #else /* configENABLE_MPU */
186     secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
187                                                                                        void * pvTaskHandle )
188 #endif /* configENABLE_MPU */
189 {
190     uint8_t * pucStackMemory = NULL;
191     uint8_t * pucStackLimit;
192     uint32_t ulIPSR, ulSecureContextIndex;
193     SecureContextHandle_t xSecureContextHandle = securecontextINVALID_CONTEXT_ID;
194
195     #if ( configENABLE_MPU == 1 )
196         uint32_t * pulCurrentStackPointer = NULL;
197     #endif /* configENABLE_MPU */
198
199     /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit
200      * Register (PSPLIM) value. */
201     secureportREAD_IPSR( ulIPSR );
202     secureportREAD_PSPLIM( pucStackLimit );
203
204     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
205      * when the processor is running in the Thread Mode.
206      * Also do nothing, if a secure context us already loaded. PSPLIM is set to
207      * securecontextNO_STACK when no secure context is loaded. */
208     if( ( ulIPSR != 0 ) && ( pucStackLimit == securecontextNO_STACK ) )
209     {
210         /* Ontain a free secure context. */
211         ulSecureContextIndex = ulGetSecureContext( pvTaskHandle );
212
213         /* Were we able to get a free context? */
214         if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS )
215         {
216             /* Allocate the stack space. */
217             pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE );
218
219             if( pucStackMemory != NULL )
220             {
221                 /* Since stack grows down, the starting point will be the last
222                 * location. Note that this location is next to the last
223                 * allocated byte for stack (excluding the space for seal values)
224                 * because the hardware decrements the stack pointer before
225                 * writing i.e. if stack pointer is 0x2, a push operation will
226                 * decrement the stack pointer to 0x1 and then write at 0x1. */
227                 xSecureContexts[ ulSecureContextIndex ].pucStackStart = pucStackMemory + ulSecureStackSize;
228
229                 /* Seal the created secure process stack. */
230                 *( uint32_t * ) ( pucStackMemory + ulSecureStackSize ) = securecontextSTACK_SEAL_VALUE;
231                 *( uint32_t * ) ( pucStackMemory + ulSecureStackSize + 4 ) = securecontextSTACK_SEAL_VALUE;
232
233                 /* The stack cannot go beyond this location. This value is
234                  * programmed in the PSPLIM register on context switch.*/
235                 xSecureContexts[ ulSecureContextIndex ].pucStackLimit = pucStackMemory;
236
237                 xSecureContexts[ ulSecureContextIndex ].pvTaskHandle = pvTaskHandle;
238
239                 #if ( configENABLE_MPU == 1 )
240                 {
241                     /* Store the correct CONTROL value for the task on the stack.
242                      * This value is programmed in the CONTROL register on
243                      * context switch. */
244                     pulCurrentStackPointer = ( uint32_t * ) xSecureContexts[ ulSecureContextIndex ].pucStackStart;
245                     pulCurrentStackPointer--;
246
247                     if( ulIsTaskPrivileged )
248                     {
249                         *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;
250                     }
251                     else
252                     {
253                         *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_UNPRIVILEGED;
254                     }
255
256                     /* Store the current stack pointer. This value is programmed in
257                      * the PSP register on context switch. */
258                     xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = ( uint8_t * ) pulCurrentStackPointer;
259                 }
260                 #else /* configENABLE_MPU */
261                 {
262                     /* Current SP is set to the starting of the stack. This
263                      * value programmed in the PSP register on context switch. */
264                     xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = xSecureContexts[ ulSecureContextIndex ].pucStackStart;
265                 }
266                 #endif /* configENABLE_MPU */
267
268                 /* Ensure to never return 0 as a valid context handle. */
269                 xSecureContextHandle = ulSecureContextIndex + 1UL;
270             }
271         }
272     }
273
274     return xSecureContextHandle;
275 }
276 /*-----------------------------------------------------------*/
277
278 secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle,
279                                                               void * pvTaskHandle )
280 {
281     uint32_t ulIPSR, ulSecureContextIndex;
282
283     /* Read the Interrupt Program Status Register (IPSR) value. */
284     secureportREAD_IPSR( ulIPSR );
285
286     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
287      * when the processor is running in the Thread Mode. */
288     if( ulIPSR != 0 )
289     {
290         /* Only free if a valid context handle is passed. */
291         if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
292         {
293             ulSecureContextIndex = xSecureContextHandle - 1UL;
294
295             /* Ensure that the secure context being deleted is associated with
296              * the task. */
297             if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle )
298             {
299                 /* Free the stack space. */
300                 vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit );
301
302                 /* Return the secure context back to the free secure contexts pool. */
303                 vReturnSecureContext( ulSecureContextIndex );
304             }
305         }
306     }
307 }
308 /*-----------------------------------------------------------*/
309
310 secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle,
311                                                               void * pvTaskHandle )
312 {
313     uint8_t * pucStackLimit;
314     uint32_t ulSecureContextIndex;
315
316     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
317     {
318         ulSecureContextIndex = xSecureContextHandle - 1UL;
319
320         secureportREAD_PSPLIM( pucStackLimit );
321
322         /* Ensure that no secure context is loaded and the task is loading it's
323          * own context. */
324         if( ( pucStackLimit == securecontextNO_STACK ) &&
325             ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
326         {
327             SecureContext_LoadContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
328         }
329     }
330 }
331 /*-----------------------------------------------------------*/
332
333 secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle,
334                                                               void * pvTaskHandle )
335 {
336     uint8_t * pucStackLimit;
337     uint32_t ulSecureContextIndex;
338
339     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
340     {
341         ulSecureContextIndex = xSecureContextHandle - 1UL;
342
343         secureportREAD_PSPLIM( pucStackLimit );
344
345         /* Ensure that task's context is loaded and the task is saving it's own
346          * context. */
347         if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) &&
348             ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
349         {
350             SecureContext_SaveContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
351         }
352     }
353 }
354 /*-----------------------------------------------------------*/