]> begriffs open source - freertos/blob - portable/ARMv8M/secure/context/secure_context.c
Pre-allocate secure-side context structures
[freertos] / portable / ARMv8M / secure / context / secure_context.c
1 /*\r
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>\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 Invalid context ID.\r
56  */\r
57 #define securecontextINVALID_CONTEXT_ID            0UL\r
58 \r
59 /**\r
60  * @brief Maximum number of secure contexts.\r
61  */\r
62 #ifndef secureconfigMAX_SECURE_CONTEXTS\r
63     #define secureconfigMAX_SECURE_CONTEXTS        8UL\r
64 #endif\r
65 /*-----------------------------------------------------------*/\r
66 \r
67 /**\r
68  * @brief Pre-allocated array of secure contexts.\r
69  */\r
70 SecureContext_t xSecureContexts[ secureconfigMAX_SECURE_CONTEXTS ];\r
71 /*-----------------------------------------------------------*/\r
72 \r
73 /**\r
74  * @brief Get a free context from the secure context pool (xSecureContexts).\r
75  *\r
76  * @return Index of a free context in the xSecureContexts array.\r
77  */\r
78 static uint32_t ulGetSecureContext( void );\r
79 \r
80 /**\r
81  * @brief Return the secure context to the secure context pool (xSecureContexts).\r
82  *\r
83  * @param[in] ulSecureContextIndex Index of the context in the xSecureContexts array.\r
84  */\r
85 static void vReturnSecureContext( uint32_t ulSecureContextIndex );\r
86 \r
87 /* These are implemented in assembly. */\r
88 extern void SecureContext_LoadContextAsm( SecureContext_t * pxSecureContext );\r
89 extern void SecureContext_SaveContextAsm( SecureContext_t * pxSecureContext );\r
90 /*-----------------------------------------------------------*/\r
91 \r
92 static uint32_t ulGetSecureContext( void )\r
93 {\r
94     uint32_t ulSecureContextIndex;\r
95 \r
96     for( ulSecureContextIndex = 0; ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS; ulSecureContextIndex++ )\r
97     {\r
98         if( ( xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer == NULL ) &&\r
99             ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == NULL ) &&\r
100             ( xSecureContexts[ ulSecureContextIndex ].pucStackStart == NULL ) )\r
101         {\r
102             break;\r
103         }\r
104     }\r
105 \r
106     return ulSecureContextIndex;\r
107 }\r
108 /*-----------------------------------------------------------*/\r
109 \r
110 static void vReturnSecureContext( uint32_t ulSecureContextIndex )\r
111 {\r
112     xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = NULL;\r
113     xSecureContexts[ ulSecureContextIndex ].pucStackLimit = NULL;\r
114     xSecureContexts[ ulSecureContextIndex ].pucStackStart = NULL;\r
115 }\r
116 /*-----------------------------------------------------------*/\r
117 \r
118 secureportNON_SECURE_CALLABLE void SecureContext_Init( void )\r
119 {\r
120     uint32_t ulIPSR, i;\r
121 \r
122     /* Read the Interrupt Program Status Register (IPSR) value. */\r
123     secureportREAD_IPSR( ulIPSR );\r
124 \r
125     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero\r
126      * when the processor is running in the Thread Mode. */\r
127     if( ulIPSR != 0 )\r
128     {\r
129         /* No stack for thread mode until a task's context is loaded. */\r
130         secureportSET_PSPLIM( securecontextNO_STACK );\r
131         secureportSET_PSP( securecontextNO_STACK );\r
132 \r
133         /* Initialize all secure contexts. */\r
134         for( i = 0; i < secureconfigMAX_SECURE_CONTEXTS; i++ )\r
135         {\r
136             xSecureContexts[ i ].pucCurrentStackPointer = NULL;\r
137             xSecureContexts[ i ].pucStackLimit = NULL;\r
138             xSecureContexts[ i ].pucStackStart = NULL;\r
139         }\r
140 \r
141         #if ( configENABLE_MPU == 1 )\r
142             {\r
143                 /* Configure thread mode to use PSP and to be unprivileged. */\r
144                 secureportSET_CONTROL( securecontextCONTROL_VALUE_UNPRIVILEGED );\r
145             }\r
146         #else /* configENABLE_MPU */\r
147             {\r
148                 /* Configure thread mode to use PSP and to be privileged. */\r
149                 secureportSET_CONTROL( securecontextCONTROL_VALUE_PRIVILEGED );\r
150             }\r
151         #endif /* configENABLE_MPU */\r
152     }\r
153 }\r
154 /*-----------------------------------------------------------*/\r
155 \r
156 #if ( configENABLE_MPU == 1 )\r
157     secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,\r
158                                                                                        uint32_t ulIsTaskPrivileged )\r
159 #else /* configENABLE_MPU */\r
160     secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize )\r
161 #endif /* configENABLE_MPU */\r
162 {\r
163     uint8_t * pucStackMemory = NULL;\r
164     uint32_t ulIPSR, ulSecureContextIndex;\r
165     SecureContextHandle_t xSecureContextHandle;\r
166 \r
167     #if ( configENABLE_MPU == 1 )\r
168         uint32_t * pulCurrentStackPointer = NULL;\r
169     #endif /* configENABLE_MPU */\r
170 \r
171     /* Read the Interrupt Program Status Register (IPSR) value. */\r
172     secureportREAD_IPSR( ulIPSR );\r
173 \r
174     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero\r
175      * when the processor is running in the Thread Mode. */\r
176     if( ulIPSR != 0 )\r
177     {\r
178         /* Ontain a free secure context. */\r
179         ulSecureContextIndex = ulGetSecureContext();\r
180 \r
181         /* Were we able to get a free context? */\r
182         if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS )\r
183         {\r
184             /* Allocate the stack space. */\r
185             pucStackMemory = pvPortMalloc( ulSecureStackSize );\r
186 \r
187             if( pucStackMemory != NULL )\r
188             {\r
189                 /* Since stack grows down, the starting point will be the last\r
190                  * location. Note that this location is next to the last\r
191                  * allocated byte because the hardware decrements the stack\r
192                  * pointer before writing i.e. if stack pointer is 0x2, a push\r
193                  * operation will decrement the stack pointer to 0x1 and then\r
194                  * write at 0x1. */\r
195                 xSecureContexts[ ulSecureContextIndex ].pucStackStart = pucStackMemory + ulSecureStackSize;\r
196 \r
197                 /* The stack cannot go beyond this location. This value is\r
198                  * programmed in the PSPLIM register on context switch.*/\r
199                 xSecureContexts[ ulSecureContextIndex ].pucStackLimit = pucStackMemory;\r
200 \r
201                 #if ( configENABLE_MPU == 1 )\r
202                     {\r
203                         /* Store the correct CONTROL value for the task on the stack.\r
204                          * This value is programmed in the CONTROL register on\r
205                          * context switch. */\r
206                         pulCurrentStackPointer = ( uint32_t * ) xSecureContexts[ ulSecureContextIndex ].pucStackStart;\r
207                         pulCurrentStackPointer--;\r
208 \r
209                         if( ulIsTaskPrivileged )\r
210                         {\r
211                             *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;\r
212                         }\r
213                         else\r
214                         {\r
215                             *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_UNPRIVILEGED;\r
216                         }\r
217 \r
218                         /* Store the current stack pointer. This value is programmed in\r
219                          * the PSP register on context switch. */\r
220                         xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = ( uint8_t * ) pulCurrentStackPointer;\r
221                     }\r
222                 #else /* configENABLE_MPU */\r
223                     {\r
224                         /* Current SP is set to the starting of the stack. This\r
225                          * value programmed in the PSP register on context switch. */\r
226                         xSecureContexts[ ulSecureContextIndex ].pucCurrentStackPointer = xSecureContexts[ ulSecureContextIndex ].pucStackStart;\r
227                     }\r
228                 #endif /* configENABLE_MPU */\r
229 \r
230                 /* Ensure to never return 0 as a valid context handle. */\r
231                 xSecureContextHandle = ulSecureContextIndex + 1UL;\r
232             }\r
233             else\r
234             {\r
235                 xSecureContextHandle = securecontextINVALID_CONTEXT_ID;\r
236             }\r
237         }\r
238     }\r
239 \r
240     return xSecureContextHandle;\r
241 }\r
242 /*-----------------------------------------------------------*/\r
243 \r
244 secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle )\r
245 {\r
246     uint32_t ulIPSR, ulSecureContextIndex;\r
247 \r
248     /* Read the Interrupt Program Status Register (IPSR) value. */\r
249     secureportREAD_IPSR( ulIPSR );\r
250 \r
251     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero\r
252      * when the processor is running in the Thread Mode. */\r
253     if( ulIPSR != 0 )\r
254     {\r
255         /* Only free if a valid context handle is passed. */\r
256         if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )\r
257         {\r
258             ulSecureContextIndex = xSecureContextHandle - 1UL;\r
259 \r
260             /* Free the stack space. */\r
261             vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit );\r
262 \r
263             /* Return the context back to the free contexts pool. */\r
264             vReturnSecureContext( ulSecureContextIndex );\r
265         }\r
266     }\r
267 }\r
268 /*-----------------------------------------------------------*/\r
269 \r
270 secureportNON_SECURE_CALLABLE void SecureContext_LoadContext( SecureContextHandle_t xSecureContextHandle )\r
271 {\r
272     uint32_t ulSecureContextIndex;\r
273 \r
274     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )\r
275     {\r
276         ulSecureContextIndex = xSecureContextHandle - 1UL;\r
277 \r
278         SecureContext_LoadContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );\r
279     }\r
280 }\r
281 /*-----------------------------------------------------------*/\r
282 \r
283 secureportNON_SECURE_CALLABLE void SecureContext_SaveContext( SecureContextHandle_t xSecureContextHandle )\r
284 {\r
285     uint32_t ulSecureContextIndex;\r
286 \r
287     if( ( xSecureContextHandle > 0UL ) && ( xSecureContextHandle <= secureconfigMAX_SECURE_CONTEXTS ) )\r
288     {\r
289         ulSecureContextIndex = xSecureContextHandle - 1UL;\r
290 \r
291         SecureContext_SaveContextAsm( &( xSecureContexts[ ulSecureContextIndex ] ) );\r
292     }\r
293 }\r
294 /*-----------------------------------------------------------*/\r