]> begriffs open source - freertos/blob - portable/GCC/ARM_CM85/secure/secure_context.c
[AUTO][RELEASE]: Bump file header version to "10.5.1"
[freertos] / portable / GCC / ARM_CM85 / secure / secure_context.c
1 /*\r
2  * FreeRTOS Kernel V10.5.1\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * SPDX-License-Identifier: MIT\r
6  *\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
13  *\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
16  *\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
23  *\r
24  * https://www.FreeRTOS.org\r
25  * https://github.com/FreeRTOS\r
26  *\r
27  */\r
28 \r
29 /* Secure context includes. */\r
30 #include "secure_context.h"\r
31 \r
32 /* Secure heap includes. */\r
33 #include "secure_heap.h"\r
34 \r
35 /* Secure port macros. */\r
36 #include "secure_port_macros.h"\r
37 \r
38 /**\r
39  * @brief CONTROL value for privileged tasks.\r
40  *\r
41  * Bit[0] - 0 --> Thread mode is privileged.\r
42  * Bit[1] - 1 --> Thread mode uses PSP.\r
43  */\r
44 #define securecontextCONTROL_VALUE_PRIVILEGED      0x02\r
45 \r
46 /**\r
47  * @brief CONTROL value for un-privileged tasks.\r
48  *\r
49  * Bit[0] - 1 --> Thread mode is un-privileged.\r
50  * Bit[1] - 1 --> Thread mode uses PSP.\r
51  */\r
52 #define securecontextCONTROL_VALUE_UNPRIVILEGED    0x03\r
53 \r
54 /**\r
55  * @brief Size of stack seal values in bytes.\r
56  */\r
57 #define securecontextSTACK_SEAL_SIZE               8\r
58 \r
59 /**\r
60  * @brief Stack seal value as recommended by ARM.\r
61  */\r
62 #define securecontextSTACK_SEAL_VALUE              0xFEF5EDA5\r
63 \r
64 /**\r
65  * @brief Maximum number of secure contexts.\r
66  */\r
67 #ifndef secureconfigMAX_SECURE_CONTEXTS\r
68     #define secureconfigMAX_SECURE_CONTEXTS        8UL\r
69 #endif\r
70 /*-----------------------------------------------------------*/\r
71 \r
72 /**\r
73  * @brief Pre-allocated array of secure contexts.\r
74  */\r
75 SecureContext_t xSecureContexts[ secureconfigMAX_SECURE_CONTEXTS ];\r
76 /*-----------------------------------------------------------*/\r
77 \r
78 /**\r
79  * @brief Get a free secure context for a task from the secure context pool (xSecureContexts).\r
80  *\r
81  * This function ensures that only one secure context is allocated for a task.\r
82  *\r
83  * @param[in] pvTaskHandle The task handle for which the secure context is allocated.\r
84  *\r
85  * @return Index of a free secure context in the xSecureContexts array.\r
86  */\r
87 static uint32_t ulGetSecureContext( void * pvTaskHandle );\r
88 \r
89 /**\r
90  * @brief Return the secure context to the secure context pool (xSecureContexts).\r
91  *\r
92  * @param[in] ulSecureContextIndex Index of the context in the xSecureContexts array.\r
93  */\r
94 static void vReturnSecureContext( uint32_t ulSecureContextIndex );\r
95 \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
100 \r
101 static uint32_t ulGetSecureContext( void * pvTaskHandle )\r
102 {\r
103     /* Start with invalid index. */\r
104     uint32_t i, ulSecureContextIndex = secureconfigMAX_SECURE_CONTEXTS;\r
105 \r
106     for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )\r
107     {\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
113         {\r
114             ulSecureContextIndex = i;\r
115         }\r
116         else if( xSecureContexts[ i ].pvTaskHandle == pvTaskHandle )\r
117         {\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
121             break;\r
122         }\r
123     }\r
124 \r
125     return ulSecureContextIndex;\r
126 }\r
127 /*-----------------------------------------------------------*/\r
128 \r
129 static void vReturnSecureContext( uint32_t ulSecureContextIndex )\r
130 {\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
135 }\r
136 /*-----------------------------------------------------------*/\r
137 \r
138 secureportNON_SECURE_CALLABLE void SecureContext_Init( void )\r
139 {\r
140     uint32_t ulIPSR, i;\r
141     static uint32_t ulSecureContextsInitialized = 0;\r
142 \r
143     /* Read the Interrupt Program Status Register (IPSR) value. */\r
144     secureportREAD_IPSR( ulIPSR );\r
145 \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
149     {\r
150         /* Ensure to initialize secure contexts only once. */\r
151         ulSecureContextsInitialized = 1;\r
152 \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
156 \r
157         /* Initialize all secure contexts. */\r
158         for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )\r
159         {\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
164         }\r
165 \r
166         #if ( configENABLE_MPU == 1 )\r
167             {\r
168                 /* Configure thread mode to use PSP and to be unprivileged. */\r
169                 secureportSET_CONTROL( securecontextCONTROL_VALUE_UNPRIVILEGED );\r
170             }\r
171         #else /* configENABLE_MPU */\r
172             {\r
173                 /* Configure thread mode to use PSP and to be privileged. */\r
174                 secureportSET_CONTROL( securecontextCONTROL_VALUE_PRIVILEGED );\r
175             }\r
176         #endif /* configENABLE_MPU */\r
177     }\r
178 }\r
179 /*-----------------------------------------------------------*/\r
180 \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
189 {\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
194 \r
195     #if ( configENABLE_MPU == 1 )\r
196         uint32_t * pulCurrentStackPointer = NULL;\r
197     #endif /* configENABLE_MPU */\r
198 \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
203 \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
209     {\r
210         /* Ontain a free secure context. */\r
211         ulSecureContextIndex = ulGetSecureContext( pvTaskHandle );\r
212 \r
213         /* Were we able to get a free context? */\r
214         if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS )\r
215         {\r
216             /* Allocate the stack space. */\r
217             pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE );\r
218 \r
219             if( pucStackMemory != NULL )\r
220             {\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
228 \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
232 \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
236 \r
237                 xSecureContexts[ ulSecureContextIndex ].pvTaskHandle = pvTaskHandle;\r
238 \r
239                 #if ( configENABLE_MPU == 1 )\r
240                     {\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
246 \r
247                         if( ulIsTaskPrivileged )\r
248                         {\r
249                             *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;\r
250                         }\r
251                         else\r
252                         {\r
253                             *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_UNPRIVILEGED;\r
254                         }\r
255 \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
259                     }\r
260                 #else /* configENABLE_MPU */\r
261                     {\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
265                     }\r
266                 #endif /* configENABLE_MPU */\r
267 \r
268                 /* Ensure to never return 0 as a valid context handle. */\r
269                 xSecureContextHandle = ulSecureContextIndex + 1UL;\r
270             }\r
271         }\r
272     }\r
273 \r
274     return xSecureContextHandle;\r
275 }\r
276 /*-----------------------------------------------------------*/\r
277 \r
278 secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )\r
279 {\r
280     uint32_t ulIPSR, ulSecureContextIndex;\r
281 \r
282     /* Read the Interrupt Program Status Register (IPSR) value. */\r
283     secureportREAD_IPSR( ulIPSR );\r
284 \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
287     if( ulIPSR != 0 )\r
288     {\r
289         /* Only free if a valid context handle is passed. */\r
290         if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )\r
291         {\r
292             ulSecureContextIndex = xSecureContextHandle - 1UL;\r
293 \r
294             /* Ensure that the secure context being deleted is associated with\r
295              * the task. */\r
296             if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle )\r
297             {\r
298                 /* Free the stack space. */\r
299                 vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit );\r
300 \r
301                 /* Return the secure context back to the free secure contexts pool. */\r
302                 vReturnSecureContext( ulSecureContextIndex );\r
303             }\r
304         }\r
305     }\r
306 }\r
307 /*-----------------------------------------------------------*/\r
308 \r
309 secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )\r
310 {\r
311     uint8_t * pucStackLimit;\r
312     uint32_t ulSecureContextIndex;\r
313 \r
314     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )\r
315     {\r
316         ulSecureContextIndex = xSecureContextHandle - 1UL;\r
317 \r
318         secureportREAD_PSPLIM( pucStackLimit );\r
319 \r
320         /* Ensure that no secure context is loaded and the task is loading it's\r
321          * own context. */\r
322         if( ( pucStackLimit == securecontextNO_STACK ) &&\r
323             ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )\r
324         {\r
325             SecureContext_LoadContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );\r
326         }\r
327     }\r
328 }\r
329 /*-----------------------------------------------------------*/\r
330 \r
331 secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle, void * pvTaskHandle )\r
332 {\r
333     uint8_t * pucStackLimit;\r
334     uint32_t ulSecureContextIndex;\r
335 \r
336     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )\r
337     {\r
338         ulSecureContextIndex = xSecureContextHandle - 1UL;\r
339 \r
340         secureportREAD_PSPLIM( pucStackLimit );\r
341 \r
342         /* Ensure that task's context is loaded and the task is saving it's own\r
343          * context. */\r
344         if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) &&\r
345             ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )\r
346         {\r
347             SecureContext_SaveContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );\r
348         }\r
349     }\r
350 }\r
351 /*-----------------------------------------------------------*/\r