]> begriffs open source - freertos/blob - portable/ARMv8M/secure/context/secure_context.c
Add SMP in the License Header (#402)
[freertos] / portable / ARMv8M / secure / context / secure_context.c
1 /*
2  * FreeRTOS SMP Kernel V202110.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /* Secure context includes. */
29 #include "secure_context.h"
30
31 /* Secure heap includes. */
32 #include "secure_heap.h"
33
34 /* Secure port macros. */
35 #include "secure_port_macros.h"
36
37 /**
38  * @brief CONTROL value for privileged tasks.
39  *
40  * Bit[0] - 0 --> Thread mode is privileged.
41  * Bit[1] - 1 --> Thread mode uses PSP.
42  */
43 #define securecontextCONTROL_VALUE_PRIVILEGED      0x02
44
45 /**
46  * @brief CONTROL value for un-privileged tasks.
47  *
48  * Bit[0] - 1 --> Thread mode is un-privileged.
49  * Bit[1] - 1 --> Thread mode uses PSP.
50  */
51 #define securecontextCONTROL_VALUE_UNPRIVILEGED    0x03
52 /*-----------------------------------------------------------*/
53
54 /**
55  * @brief Structure to represent secure context.
56  *
57  * @note Since stack grows down, pucStackStart is the highest address while
58  * pucStackLimit is the first addess of the allocated memory.
59  */
60 typedef struct SecureContext
61 {
62     uint8_t * pucCurrentStackPointer; /**< Current value of stack pointer (PSP). */
63     uint8_t * pucStackLimit;          /**< Last location of the stack memory (PSPLIM). */
64     uint8_t * pucStackStart;          /**< First location of the stack memory. */
65 } SecureContext_t;
66 /*-----------------------------------------------------------*/
67
68 secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
69 {
70     uint32_t ulIPSR;
71
72     /* Read the Interrupt Program Status Register (IPSR) value. */
73     secureportREAD_IPSR( ulIPSR );
74
75     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
76      * when the processor is running in the Thread Mode. */
77     if( ulIPSR != 0 )
78     {
79         /* No stack for thread mode until a task's context is loaded. */
80         secureportSET_PSPLIM( securecontextNO_STACK );
81         secureportSET_PSP( securecontextNO_STACK );
82
83         #if ( configENABLE_MPU == 1 )
84             {
85                 /* Configure thread mode to use PSP and to be unprivileged. */
86                 secureportSET_CONTROL( securecontextCONTROL_VALUE_UNPRIVILEGED );
87             }
88         #else /* configENABLE_MPU */
89             {
90                 /* Configure thread mode to use PSP and to be privileged.. */
91                 secureportSET_CONTROL( securecontextCONTROL_VALUE_PRIVILEGED );
92             }
93         #endif /* configENABLE_MPU */
94     }
95 }
96 /*-----------------------------------------------------------*/
97
98 #if ( configENABLE_MPU == 1 )
99     secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
100                                                                                        uint32_t ulIsTaskPrivileged )
101 #else /* configENABLE_MPU */
102     secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize )
103 #endif /* configENABLE_MPU */
104 {
105     uint8_t * pucStackMemory = NULL;
106     uint32_t ulIPSR;
107     SecureContextHandle_t xSecureContextHandle = NULL;
108
109     #if ( configENABLE_MPU == 1 )
110         uint32_t * pulCurrentStackPointer = NULL;
111     #endif /* configENABLE_MPU */
112
113     /* Read the Interrupt Program Status Register (IPSR) value. */
114     secureportREAD_IPSR( ulIPSR );
115
116     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
117      * when the processor is running in the Thread Mode. */
118     if( ulIPSR != 0 )
119     {
120         /* Allocate the context structure. */
121         xSecureContextHandle = ( SecureContextHandle_t ) pvPortMalloc( sizeof( SecureContext_t ) );
122
123         if( xSecureContextHandle != NULL )
124         {
125             /* Allocate the stack space. */
126             pucStackMemory = pvPortMalloc( ulSecureStackSize );
127
128             if( pucStackMemory != NULL )
129             {
130                 /* Since stack grows down, the starting point will be the last
131                  * location. Note that this location is next to the last
132                  * allocated byte because the hardware decrements the stack
133                  * pointer before writing i.e. if stack pointer is 0x2, a push
134                  * operation will decrement the stack pointer to 0x1 and then
135                  * write at 0x1. */
136                 xSecureContextHandle->pucStackStart = pucStackMemory + ulSecureStackSize;
137
138                 /* The stack cannot go beyond this location. This value is
139                  * programmed in the PSPLIM register on context switch.*/
140                 xSecureContextHandle->pucStackLimit = pucStackMemory;
141
142                 #if ( configENABLE_MPU == 1 )
143                     {
144                         /* Store the correct CONTROL value for the task on the stack.
145                          * This value is programmed in the CONTROL register on
146                          * context switch. */
147                         pulCurrentStackPointer = ( uint32_t * ) xSecureContextHandle->pucStackStart;
148                         pulCurrentStackPointer--;
149
150                         if( ulIsTaskPrivileged )
151                         {
152                             *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;
153                         }
154                         else
155                         {
156                             *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_UNPRIVILEGED;
157                         }
158
159                         /* Store the current stack pointer. This value is programmed in
160                          * the PSP register on context switch. */
161                         xSecureContextHandle->pucCurrentStackPointer = ( uint8_t * ) pulCurrentStackPointer;
162                     }
163                 #else /* configENABLE_MPU */
164                     {
165                         /* Current SP is set to the starting of the stack. This
166                          * value programmed in the PSP register on context switch. */
167                         xSecureContextHandle->pucCurrentStackPointer = xSecureContextHandle->pucStackStart;
168                     }
169                 #endif /* configENABLE_MPU */
170             }
171             else
172             {
173                 /* Free the context to avoid memory leak and make sure to return
174                  * NULL to indicate failure. */
175                 vPortFree( xSecureContextHandle );
176                 xSecureContextHandle = NULL;
177             }
178         }
179     }
180
181     return xSecureContextHandle;
182 }
183 /*-----------------------------------------------------------*/
184
185 secureportNON_SECURE_CALLABLE void SecureContext_FreeContext( SecureContextHandle_t xSecureContextHandle )
186 {
187     uint32_t ulIPSR;
188
189     /* Read the Interrupt Program Status Register (IPSR) value. */
190     secureportREAD_IPSR( ulIPSR );
191
192     /* Do nothing if the processor is running in the Thread Mode. IPSR is zero
193      * when the processor is running in the Thread Mode. */
194     if( ulIPSR != 0 )
195     {
196         /* Ensure that valid parameters are passed. */
197         secureportASSERT( xSecureContextHandle != NULL );
198
199         /* Free the stack space. */
200         vPortFree( xSecureContextHandle->pucStackLimit );
201
202         /* Free the context itself. */
203         vPortFree( xSecureContextHandle );
204     }
205 }
206 /*-----------------------------------------------------------*/