2 * FreeRTOS Kernel V10.4.4
\r
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * SPDX-License-Identifier: MIT
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
14 * The above copyright notice and this permission notice shall be included in all
\r
15 * copies or substantial portions of the Software.
\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
24 * https://www.FreeRTOS.org
\r
25 * https://github.com/FreeRTOS
\r
28 /* Including FreeRTOSConfig.h here will cause build errors if the header file
\r
29 contains code not understood by the assembler - for example the 'extern' keyword.
\r
30 To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so
\r
31 the code is included in C files but excluded by the preprocessor in assembly
\r
32 files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler. */
\r
33 #include "FreeRTOSConfig.h"
\r
36 EXTERN xSecureContext
\r
37 EXTERN vTaskSwitchContext
\r
38 EXTERN vPortSVCHandler_C
\r
39 EXTERN SecureContext_SaveContext
\r
40 EXTERN SecureContext_LoadContext
\r
42 PUBLIC xIsPrivileged
\r
43 PUBLIC vResetPrivilege
\r
44 PUBLIC vPortAllocateSecureContext
\r
45 PUBLIC vRestoreContextOfFirstTask
\r
46 PUBLIC vRaisePrivilege
\r
47 PUBLIC vStartFirstTask
\r
48 PUBLIC ulSetInterruptMask
\r
49 PUBLIC vClearInterruptMask
\r
50 PUBLIC PendSV_Handler
\r
52 PUBLIC vPortFreeSecureContext
\r
53 /*-----------------------------------------------------------*/
\r
55 /*---------------- Unprivileged Functions -------------------*/
\r
57 /*-----------------------------------------------------------*/
\r
59 SECTION .text:CODE:NOROOT(2)
\r
61 /*-----------------------------------------------------------*/
\r
64 mrs r0, control /* r0 = CONTROL. */
\r
65 tst r0, #1 /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
\r
67 movne r0, #0 /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
\r
68 moveq r0, #1 /* CONTROL[0]==0. Return true to indicate that the processor is not privileged. */
\r
70 /*-----------------------------------------------------------*/
\r
73 mrs r0, control /* r0 = CONTROL. */
\r
74 orr r0, r0, #1 /* r0 = r0 | 1. */
\r
75 msr control, r0 /* CONTROL = r0. */
\r
76 bx lr /* Return to the caller. */
\r
77 /*-----------------------------------------------------------*/
\r
79 vPortAllocateSecureContext:
\r
80 svc 0 /* Secure context is allocated in the supervisor call. portSVC_ALLOCATE_SECURE_CONTEXT = 0. */
\r
82 /*-----------------------------------------------------------*/
\r
84 /*----------------- Privileged Functions --------------------*/
\r
86 /*-----------------------------------------------------------*/
\r
88 SECTION privileged_functions:CODE:NOROOT(2)
\r
90 /*-----------------------------------------------------------*/
\r
92 vRestoreContextOfFirstTask:
\r
93 ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
94 ldr r3, [r2] /* Read pxCurrentTCB. */
\r
95 ldr r0, [r3] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
\r
97 #if ( configENABLE_MPU == 1 )
\r
98 dmb /* Complete outstanding transfers before disabling MPU. */
\r
99 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
100 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
101 bic r4, r4, #1 /* r4 = r4 & ~1 i.e. Clear the bit 0 in r4. */
\r
102 str r4, [r2] /* Disable MPU. */
\r
104 adds r3, #4 /* r3 = r3 + 4. r3 now points to MAIR0 in TCB. */
\r
105 ldr r4, [r3] /* r4 = *r3 i.e. r4 = MAIR0. */
\r
106 ldr r2, =0xe000edc0 /* r2 = 0xe000edc0 [Location of MAIR0]. */
\r
107 str r4, [r2] /* Program MAIR0. */
\r
108 ldr r2, =0xe000ed98 /* r2 = 0xe000ed98 [Location of RNR]. */
\r
109 movs r4, #4 /* r4 = 4. */
\r
110 str r4, [r2] /* Program RNR = 4. */
\r
111 adds r3, #4 /* r3 = r3 + 4. r3 now points to first RBAR in TCB. */
\r
112 ldr r2, =0xe000ed9c /* r2 = 0xe000ed9c [Location of RBAR]. */
\r
113 ldmia r3!, {r4-r11} /* Read 4 set of RBAR/RLAR registers from TCB. */
\r
114 stmia r2!, {r4-r11} /* Write 4 set of RBAR/RLAR registers using alias registers. */
\r
116 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
117 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
118 orr r4, r4, #1 /* r4 = r4 | 1 i.e. Set the bit 0 in r4. */
\r
119 str r4, [r2] /* Enable MPU. */
\r
120 dsb /* Force memory writes before continuing. */
\r
121 #endif /* configENABLE_MPU */
\r
123 #if ( configENABLE_MPU == 1 )
\r
124 ldm r0!, {r1-r4} /* Read from stack - r1 = xSecureContext, r2 = PSPLIM, r3 = CONTROL and r4 = EXC_RETURN. */
\r
125 ldr r5, =xSecureContext
\r
126 str r1, [r5] /* Set xSecureContext to this task's value for the same. */
\r
127 msr psplim, r2 /* Set this task's PSPLIM value. */
\r
128 msr control, r3 /* Set this task's CONTROL value. */
\r
129 adds r0, #32 /* Discard everything up to r0. */
\r
130 msr psp, r0 /* This is now the new top of stack to use in the task. */
\r
133 msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
\r
134 bx r4 /* Finally, branch to EXC_RETURN. */
\r
135 #else /* configENABLE_MPU */
\r
136 ldm r0!, {r1-r3} /* Read from stack - r1 = xSecureContext, r2 = PSPLIM and r3 = EXC_RETURN. */
\r
137 ldr r4, =xSecureContext
\r
138 str r1, [r4] /* Set xSecureContext to this task's value for the same. */
\r
139 msr psplim, r2 /* Set this task's PSPLIM value. */
\r
140 movs r1, #2 /* r1 = 2. */
\r
141 msr CONTROL, r1 /* Switch to use PSP in the thread mode. */
\r
142 adds r0, #32 /* Discard everything up to r0. */
\r
143 msr psp, r0 /* This is now the new top of stack to use in the task. */
\r
146 msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
\r
147 bx r3 /* Finally, branch to EXC_RETURN. */
\r
148 #endif /* configENABLE_MPU */
\r
149 /*-----------------------------------------------------------*/
\r
152 mrs r0, control /* Read the CONTROL register. */
\r
153 bic r0, r0, #1 /* Clear the bit 0. */
\r
154 msr control, r0 /* Write back the new CONTROL value. */
\r
155 bx lr /* Return to the caller. */
\r
156 /*-----------------------------------------------------------*/
\r
159 ldr r0, =0xe000ed08 /* Use the NVIC offset register to locate the stack. */
\r
160 ldr r0, [r0] /* Read the VTOR register which gives the address of vector table. */
\r
161 ldr r0, [r0] /* The first entry in vector table is stack pointer. */
\r
162 msr msp, r0 /* Set the MSP back to the start of the stack. */
\r
163 cpsie i /* Globally enable interrupts. */
\r
167 svc 2 /* System call to start the first task. portSVC_START_SCHEDULER = 2. */
\r
168 /*-----------------------------------------------------------*/
\r
170 ulSetInterruptMask:
\r
171 mrs r0, basepri /* r0 = basepri. Return original basepri value. */
\r
172 mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
173 msr basepri, r1 /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
\r
176 bx lr /* Return. */
\r
177 /*-----------------------------------------------------------*/
\r
179 vClearInterruptMask:
\r
180 msr basepri, r0 /* basepri = ulMask. */
\r
183 bx lr /* Return. */
\r
184 /*-----------------------------------------------------------*/
\r
187 mrs r1, psp /* Read PSP in r1. */
\r
188 ldr r2, =xSecureContext /* Read the location of xSecureContext i.e. &( xSecureContext ). */
\r
189 ldr r0, [r2] /* Read xSecureContext - Value of xSecureContext must be in r0 as it is used as a parameter later. */
\r
191 cbz r0, save_ns_context /* No secure context to save. */
\r
193 bl SecureContext_SaveContext
\r
194 pop {r0-r3} /* LR is now in r3. */
\r
195 mov lr, r3 /* LR = r3. */
\r
196 lsls r2, r3, #25 /* r2 = r3 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
\r
197 bpl save_ns_context /* bpl - branch if positive or zero. If r2 >= 0 ==> Bit[6] in EXC_RETURN is 0 i.e. non-secure stack was used. */
\r
198 ldr r3, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
199 ldr r2, [r3] /* Read pxCurrentTCB. */
\r
200 #if ( configENABLE_MPU == 1 )
\r
201 subs r1, r1, #16 /* Make space for xSecureContext, PSPLIM, CONTROL and LR on the stack. */
\r
202 str r1, [r2] /* Save the new top of stack in TCB. */
\r
203 mrs r2, psplim /* r2 = PSPLIM. */
\r
204 mrs r3, control /* r3 = CONTROL. */
\r
205 mov r4, lr /* r4 = LR/EXC_RETURN. */
\r
206 stmia r1!, {r0, r2-r4} /* Store xSecureContext, PSPLIM, CONTROL and LR on the stack. */
\r
207 #else /* configENABLE_MPU */
\r
208 subs r1, r1, #12 /* Make space for xSecureContext, PSPLIM and LR on the stack. */
\r
209 str r1, [r2] /* Save the new top of stack in TCB. */
\r
210 mrs r2, psplim /* r2 = PSPLIM. */
\r
211 mov r3, lr /* r3 = LR/EXC_RETURN. */
\r
212 stmia r1!, {r0, r2-r3} /* Store xSecureContext, PSPLIM and LR on the stack. */
\r
213 #endif /* configENABLE_MPU */
\r
217 ldr r3, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
218 ldr r2, [r3] /* Read pxCurrentTCB. */
\r
219 #if ( configENABLE_FPU == 1 )
\r
220 tst lr, #0x10 /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the FPU is in use. */
\r
222 vstmdbeq r1!, {s16-s31} /* Store the FPU registers which are not saved automatically. */
\r
223 #endif /* configENABLE_FPU */
\r
224 #if ( configENABLE_MPU == 1 )
\r
225 subs r1, r1, #48 /* Make space for xSecureContext, PSPLIM, CONTROL, LR and the remaining registers on the stack. */
\r
226 str r1, [r2] /* Save the new top of stack in TCB. */
\r
227 adds r1, r1, #16 /* r1 = r1 + 16. */
\r
228 stm r1, {r4-r11} /* Store the registers that are not saved automatically. */
\r
229 mrs r2, psplim /* r2 = PSPLIM. */
\r
230 mrs r3, control /* r3 = CONTROL. */
\r
231 mov r4, lr /* r4 = LR/EXC_RETURN. */
\r
232 subs r1, r1, #16 /* r1 = r1 - 16. */
\r
233 stm r1, {r0, r2-r4} /* Store xSecureContext, PSPLIM, CONTROL and LR on the stack. */
\r
234 #else /* configENABLE_MPU */
\r
235 subs r1, r1, #44 /* Make space for xSecureContext, PSPLIM, LR and the remaining registers on the stack. */
\r
236 str r1, [r2] /* Save the new top of stack in TCB. */
\r
237 adds r1, r1, #12 /* r1 = r1 + 12. */
\r
238 stm r1, {r4-r11} /* Store the registers that are not saved automatically. */
\r
239 mrs r2, psplim /* r2 = PSPLIM. */
\r
240 mov r3, lr /* r3 = LR/EXC_RETURN. */
\r
241 subs r1, r1, #12 /* r1 = r1 - 12. */
\r
242 stmia r1!, {r0, r2-r3} /* Store xSecureContext, PSPLIM and LR on the stack. */
\r
243 #endif /* configENABLE_MPU */
\r
246 mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
247 msr basepri, r0 /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
\r
250 bl vTaskSwitchContext
\r
251 mov r0, #0 /* r0 = 0. */
\r
252 msr basepri, r0 /* Enable interrupts. */
\r
254 ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
255 ldr r3, [r2] /* Read pxCurrentTCB. */
\r
256 ldr r1, [r3] /* The first item in pxCurrentTCB is the task top of stack. r1 now points to the top of stack. */
\r
258 #if ( configENABLE_MPU == 1 )
\r
259 dmb /* Complete outstanding transfers before disabling MPU. */
\r
260 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
261 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
262 bic r4, r4, #1 /* r4 = r4 & ~1 i.e. Clear the bit 0 in r4. */
\r
263 str r4, [r2] /* Disable MPU. */
\r
265 adds r3, #4 /* r3 = r3 + 4. r3 now points to MAIR0 in TCB. */
\r
266 ldr r4, [r3] /* r4 = *r3 i.e. r4 = MAIR0. */
\r
267 ldr r2, =0xe000edc0 /* r2 = 0xe000edc0 [Location of MAIR0]. */
\r
268 str r4, [r2] /* Program MAIR0. */
\r
269 ldr r2, =0xe000ed98 /* r2 = 0xe000ed98 [Location of RNR]. */
\r
270 movs r4, #4 /* r4 = 4. */
\r
271 str r4, [r2] /* Program RNR = 4. */
\r
272 adds r3, #4 /* r3 = r3 + 4. r3 now points to first RBAR in TCB. */
\r
273 ldr r2, =0xe000ed9c /* r2 = 0xe000ed9c [Location of RBAR]. */
\r
274 ldmia r3!, {r4-r11} /* Read 4 sets of RBAR/RLAR registers from TCB. */
\r
275 stmia r2!, {r4-r11} /* Write 4 set of RBAR/RLAR registers using alias registers. */
\r
277 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
278 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
279 orr r4, r4, #1 /* r4 = r4 | 1 i.e. Set the bit 0 in r4. */
\r
280 str r4, [r2] /* Enable MPU. */
\r
281 dsb /* Force memory writes before continuing. */
\r
282 #endif /* configENABLE_MPU */
\r
284 #if ( configENABLE_MPU == 1 )
\r
285 ldmia r1!, {r0, r2-r4} /* Read from stack - r0 = xSecureContext, r2 = PSPLIM, r3 = CONTROL and r4 = LR. */
\r
286 msr psplim, r2 /* Restore the PSPLIM register value for the task. */
\r
287 msr control, r3 /* Restore the CONTROL register value for the task. */
\r
288 mov lr, r4 /* LR = r4. */
\r
289 ldr r2, =xSecureContext /* Read the location of xSecureContext i.e. &( xSecureContext ). */
\r
290 str r0, [r2] /* Restore the task's xSecureContext. */
\r
291 cbz r0, restore_ns_context /* If there is no secure context for the task, restore the non-secure context. */
\r
293 bl SecureContext_LoadContext /* Restore the secure context. */
\r
295 mov lr, r4 /* LR = r4. */
\r
296 lsls r2, r4, #25 /* r2 = r4 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
\r
297 bpl restore_ns_context /* bpl - branch if positive or zero. If r2 >= 0 ==> Bit[6] in EXC_RETURN is 0 i.e. non-secure stack was used. */
\r
298 msr psp, r1 /* Remember the new top of stack for the task. */
\r
300 #else /* configENABLE_MPU */
\r
301 ldmia r1!, {r0, r2-r3} /* Read from stack - r0 = xSecureContext, r2 = PSPLIM and r3 = LR. */
\r
302 msr psplim, r2 /* Restore the PSPLIM register value for the task. */
\r
303 mov lr, r3 /* LR = r3. */
\r
304 ldr r2, =xSecureContext /* Read the location of xSecureContext i.e. &( xSecureContext ). */
\r
305 str r0, [r2] /* Restore the task's xSecureContext. */
\r
306 cbz r0, restore_ns_context /* If there is no secure context for the task, restore the non-secure context. */
\r
308 bl SecureContext_LoadContext /* Restore the secure context. */
\r
310 mov lr, r3 /* LR = r3. */
\r
311 lsls r2, r3, #25 /* r2 = r3 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
\r
312 bpl restore_ns_context /* bpl - branch if positive or zero. If r2 >= 0 ==> Bit[6] in EXC_RETURN is 0 i.e. non-secure stack was used. */
\r
313 msr psp, r1 /* Remember the new top of stack for the task. */
\r
315 #endif /* configENABLE_MPU */
\r
317 restore_ns_context:
\r
318 ldmia r1!, {r4-r11} /* Restore the registers that are not automatically restored. */
\r
319 #if ( configENABLE_FPU == 1 )
\r
320 tst lr, #0x10 /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the FPU is in use. */
\r
322 vldmiaeq r1!, {s16-s31} /* Restore the FPU registers which are not restored automatically. */
\r
323 #endif /* configENABLE_FPU */
\r
324 msr psp, r1 /* Remember the new top of stack for the task. */
\r
326 /*-----------------------------------------------------------*/
\r
333 b vPortSVCHandler_C
\r
334 /*-----------------------------------------------------------*/
\r
336 vPortFreeSecureContext:
\r
337 /* r0 = uint32_t *pulTCB. */
\r
338 ldr r1, [r0] /* The first item in the TCB is the top of the stack. */
\r
339 ldr r0, [r1] /* The first item on the stack is the task's xSecureContext. */
\r
340 cmp r0, #0 /* Raise svc if task's xSecureContext is not NULL. */
\r
342 svcne 1 /* Secure context is freed in the supervisor call. portSVC_FREE_SECURE_CONTEXT = 1. */
\r
343 bx lr /* Return. */
\r
344 /*-----------------------------------------------------------*/
\r