xref: /Kernel-v10.6.2/portable/GCC/ARM_CM33/secure/secure_context.c (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1 /*
2  * FreeRTOS Kernel V10.6.2
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 
ulGetSecureContext(void * pvTaskHandle)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 
vReturnSecureContext(uint32_t ulSecureContextIndex)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 
SecureContext_Init(void)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 )
SecureContext_AllocateContext(uint32_t ulSecureStackSize,uint32_t ulIsTaskPrivileged,void * pvTaskHandle)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 
SecureContext_FreeContext(SecureContextHandle_t xSecureContextHandle,void * pvTaskHandle)278 secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )
279 {
280     uint32_t ulIPSR, ulSecureContextIndex;
281 
282     /* Read the Interrupt Program Status Register (IPSR) value. */
283     secureportREAD_IPSR( ulIPSR );
284 
285     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
286      * when the processor is running in the Thread Mode. */
287     if( ulIPSR != 0 )
288     {
289         /* Only free if a valid context handle is passed. */
290         if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
291         {
292             ulSecureContextIndex = xSecureContextHandle - 1UL;
293 
294             /* Ensure that the secure context being deleted is associated with
295              * the task. */
296             if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle )
297             {
298                 /* Free the stack space. */
299                 vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit );
300 
301                 /* Return the secure context back to the free secure contexts pool. */
302                 vReturnSecureContext( ulSecureContextIndex );
303             }
304         }
305     }
306 }
307 /*-----------------------------------------------------------*/
308 
SecureContext_LoadContext(SecureContextHandle_t xSecureContextHandle,void * pvTaskHandle)309 secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )
310 {
311     uint8_t * pucStackLimit;
312     uint32_t ulSecureContextIndex;
313 
314     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
315     {
316         ulSecureContextIndex = xSecureContextHandle - 1UL;
317 
318         secureportREAD_PSPLIM( pucStackLimit );
319 
320         /* Ensure that no secure context is loaded and the task is loading it's
321          * own context. */
322         if( ( pucStackLimit == securecontextNO_STACK ) &&
323             ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
324         {
325             SecureContext_LoadContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
326         }
327     }
328 }
329 /*-----------------------------------------------------------*/
330 
SecureContext_SaveContext(SecureContextHandle_t xSecureContextHandle,void * pvTaskHandle)331 secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )
332 {
333     uint8_t * pucStackLimit;
334     uint32_t ulSecureContextIndex;
335 
336     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )
337     {
338         ulSecureContextIndex = xSecureContextHandle - 1UL;
339 
340         secureportREAD_PSPLIM( pucStackLimit );
341 
342         /* Ensure that task's context is loaded and the task is saving it's own
343          * context. */
344         if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) &&
345             ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
346         {
347             SecureContext_SaveContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );
348         }
349     }
350 }
351 /*-----------------------------------------------------------*/
352