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