2 * FreeRTOS Kernel V10.3.0
\r
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 EXTERN xSecureContext
\r
30 EXTERN vTaskSwitchContext
\r
31 EXTERN vPortSVCHandler_C
\r
32 EXTERN SecureContext_SaveContext
\r
33 EXTERN SecureContext_LoadContext
\r
35 PUBLIC xIsPrivileged
\r
36 PUBLIC vResetPrivilege
\r
37 PUBLIC vPortAllocateSecureContext
\r
38 PUBLIC vRestoreContextOfFirstTask
\r
39 PUBLIC vRaisePrivilege
\r
40 PUBLIC vStartFirstTask
\r
41 PUBLIC ulSetInterruptMask
\r
42 PUBLIC vClearInterruptMask
\r
43 PUBLIC PendSV_Handler
\r
45 PUBLIC vPortFreeSecureContext
\r
47 #if ( configENABLE_FPU == 1 )
\r
48 #error Cortex-M23 does not have a Floating Point Unit (FPU) and therefore configENABLE_FPU must be set to 0.
\r
50 /*-----------------------------------------------------------*/
\r
52 /*---------------- Unprivileged Functions -------------------*/
\r
54 /*-----------------------------------------------------------*/
\r
56 SECTION .text:CODE:NOROOT(2)
\r
58 /*-----------------------------------------------------------*/
\r
61 mrs r0, control /* r0 = CONTROL. */
\r
62 movs r1, #1 /* r1 = 1. */
\r
63 tst r0, r1 /* Perform r0 & r1 (bitwise AND) and update the conditions flag. */
\r
64 beq running_privileged /* If the result of previous AND operation was 0, branch. */
\r
65 movs r0, #0 /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
\r
68 movs r0, #1 /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */
\r
70 /*-----------------------------------------------------------*/
\r
73 mrs r0, control /* r0 = CONTROL. */
\r
74 movs r1, #1 /* r1 = 1. */
\r
75 orrs r0, r1 /* r0 = r0 | r1. */
\r
76 msr control, r0 /* CONTROL = r0. */
\r
77 bx lr /* Return to the caller. */
\r
78 /*-----------------------------------------------------------*/
\r
80 vPortAllocateSecureContext:
\r
81 svc 0 /* Secure context is allocated in the supervisor call. portSVC_ALLOCATE_SECURE_CONTEXT = 0. */
\r
83 /*-----------------------------------------------------------*/
\r
85 /*----------------- Privileged Functions --------------------*/
\r
87 /*-----------------------------------------------------------*/
\r
89 SECTION privileged_functions:CODE:NOROOT(2)
\r
91 /*-----------------------------------------------------------*/
\r
93 vRestoreContextOfFirstTask:
\r
94 ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
95 ldr r3, [r2] /* Read pxCurrentTCB. */
\r
96 ldr r0, [r3] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
\r
98 #if ( configENABLE_MPU == 1 )
\r
99 dmb /* Complete outstanding transfers before disabling MPU. */
\r
100 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
101 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
102 movs r5, #1 /* r5 = 1. */
\r
103 bics r4, r5 /* r4 = r4 & ~r5 i.e. Clear the bit 0 in r4. */
\r
104 str r4, [r2] /* Disable MPU. */
\r
106 adds r3, #4 /* r3 = r3 + 4. r3 now points to MAIR0 in TCB. */
\r
107 ldr r4, [r3] /* r4 = *r3 i.e. r4 = MAIR0. */
\r
108 ldr r2, =0xe000edc0 /* r2 = 0xe000edc0 [Location of MAIR0]. */
\r
109 str r4, [r2] /* Program MAIR0. */
\r
110 ldr r2, =0xe000ed98 /* r2 = 0xe000ed98 [Location of RNR]. */
\r
111 adds r3, #4 /* r3 = r3 + 4. r3 now points to first RBAR in TCB. */
\r
112 movs r5, #4 /* r5 = 4. */
\r
113 str r5, [r2] /* Program RNR = 4. */
\r
114 ldmia r3!, {r6,r7} /* Read first set of RBAR/RLAR from TCB. */
\r
115 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
116 stmia r4!, {r6,r7} /* Write first set of RBAR/RLAR registers. */
\r
117 movs r5, #5 /* r5 = 5. */
\r
118 str r5, [r2] /* Program RNR = 5. */
\r
119 ldmia r3!, {r6,r7} /* Read second set of RBAR/RLAR from TCB. */
\r
120 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
121 stmia r4!, {r6,r7} /* Write second set of RBAR/RLAR registers. */
\r
122 movs r5, #6 /* r5 = 6. */
\r
123 str r5, [r2] /* Program RNR = 6. */
\r
124 ldmia r3!, {r6,r7} /* Read third set of RBAR/RLAR from TCB. */
\r
125 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
126 stmia r4!, {r6,r7} /* Write third set of RBAR/RLAR registers. */
\r
127 movs r5, #7 /* r5 = 7. */
\r
128 str r5, [r2] /* Program RNR = 7. */
\r
129 ldmia r3!, {r6,r7} /* Read fourth set of RBAR/RLAR from TCB. */
\r
130 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
131 stmia r4!, {r6,r7} /* Write fourth set of RBAR/RLAR registers. */
\r
133 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
134 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
135 movs r5, #1 /* r5 = 1. */
\r
136 orrs r4, r5 /* r4 = r4 | r5 i.e. Set the bit 0 in r4. */
\r
137 str r4, [r2] /* Enable MPU. */
\r
138 dsb /* Force memory writes before continuing. */
\r
139 #endif /* configENABLE_MPU */
\r
141 #if ( configENABLE_MPU == 1 )
\r
142 ldm r0!, {r1-r4} /* Read from stack - r1 = xSecureContext, r2 = PSPLIM, r3 = CONTROL and r4 = EXC_RETURN. */
\r
143 ldr r5, =xSecureContext
\r
144 str r1, [r5] /* Set xSecureContext to this task's value for the same. */
\r
145 msr psplim, r2 /* Set this task's PSPLIM value. */
\r
146 msr control, r3 /* Set this task's CONTROL value. */
\r
147 adds r0, #32 /* Discard everything up to r0. */
\r
148 msr psp, r0 /* This is now the new top of stack to use in the task. */
\r
150 bx r4 /* Finally, branch to EXC_RETURN. */
\r
151 #else /* configENABLE_MPU */
\r
152 ldm r0!, {r1-r3} /* Read from stack - r1 = xSecureContext, r2 = PSPLIM and r3 = EXC_RETURN. */
\r
153 ldr r4, =xSecureContext
\r
154 str r1, [r4] /* Set xSecureContext to this task's value for the same. */
\r
155 msr psplim, r2 /* Set this task's PSPLIM value. */
\r
156 movs r1, #2 /* r1 = 2. */
\r
157 msr CONTROL, r1 /* Switch to use PSP in the thread mode. */
\r
158 adds r0, #32 /* Discard everything up to r0. */
\r
159 msr psp, r0 /* This is now the new top of stack to use in the task. */
\r
161 bx r3 /* Finally, branch to EXC_RETURN. */
\r
162 #endif /* configENABLE_MPU */
\r
163 /*-----------------------------------------------------------*/
\r
166 mrs r0, control /* Read the CONTROL register. */
\r
167 movs r1, #1 /* r1 = 1. */
\r
168 bics r0, r1 /* Clear the bit 0. */
\r
169 msr control, r0 /* Write back the new CONTROL value. */
\r
170 bx lr /* Return to the caller. */
\r
171 /*-----------------------------------------------------------*/
\r
174 ldr r0, =0xe000ed08 /* Use the NVIC offset register to locate the stack. */
\r
175 ldr r0, [r0] /* Read the VTOR register which gives the address of vector table. */
\r
176 ldr r0, [r0] /* The first entry in vector table is stack pointer. */
\r
177 msr msp, r0 /* Set the MSP back to the start of the stack. */
\r
178 cpsie i /* Globally enable interrupts. */
\r
181 svc 2 /* System call to start the first task. portSVC_START_SCHEDULER = 2. */
\r
182 /*-----------------------------------------------------------*/
\r
184 ulSetInterruptMask:
\r
188 /*-----------------------------------------------------------*/
\r
190 vClearInterruptMask:
\r
193 /*-----------------------------------------------------------*/
\r
196 mrs r1, psp /* Read PSP in r1. */
\r
197 ldr r2, =xSecureContext /* Read the location of xSecureContext i.e. &( xSecureContext ). */
\r
198 ldr r0, [r2] /* Read xSecureContext - Value of xSecureContext must be in r0 as it is used as a parameter later. */
\r
200 cbz r0, save_ns_context /* No secure context to save. */
\r
202 bl SecureContext_SaveContext
\r
203 pop {r0-r3} /* LR is now in r3. */
\r
204 mov lr, r3 /* LR = r3. */
\r
205 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
206 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
207 ldr r3, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
208 ldr r2, [r3] /* Read pxCurrentTCB. */
\r
209 #if ( configENABLE_MPU == 1 )
\r
210 subs r1, r1, #16 /* Make space for xSecureContext, PSPLIM, CONTROL and LR on the stack. */
\r
211 str r1, [r2] /* Save the new top of stack in TCB. */
\r
212 mrs r2, psplim /* r2 = PSPLIM. */
\r
213 mrs r3, control /* r3 = CONTROL. */
\r
214 mov r4, lr /* r4 = LR/EXC_RETURN. */
\r
215 stmia r1!, {r0, r2-r4} /* Store xSecureContext, PSPLIM, CONTROL and LR on the stack. */
\r
216 #else /* configENABLE_MPU */
\r
217 subs r1, r1, #12 /* Make space for xSecureContext, PSPLIM and LR on the stack. */
\r
218 str r1, [r2] /* Save the new top of stack in TCB. */
\r
219 mrs r2, psplim /* r2 = PSPLIM. */
\r
220 mov r3, lr /* r3 = LR/EXC_RETURN. */
\r
221 stmia r1!, {r0, r2-r3} /* Store xSecureContext, PSPLIM and LR on the stack. */
\r
222 #endif /* configENABLE_MPU */
\r
226 ldr r3, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
227 ldr r2, [r3] /* Read pxCurrentTCB. */
\r
228 #if ( configENABLE_MPU == 1 )
\r
229 subs r1, r1, #48 /* Make space for xSecureContext, PSPLIM, CONTROL, LR and the remaining registers on the stack. */
\r
230 str r1, [r2] /* Save the new top of stack in TCB. */
\r
231 adds r1, r1, #16 /* r1 = r1 + 16. */
\r
232 stmia r1!, {r4-r7} /* Store the low registers that are not saved automatically. */
\r
233 mov r4, r8 /* r4 = r8. */
\r
234 mov r5, r9 /* r5 = r9. */
\r
235 mov r6, r10 /* r6 = r10. */
\r
236 mov r7, r11 /* r7 = r11. */
\r
237 stmia r1!, {r4-r7} /* Store the high registers that are not saved automatically. */
\r
238 mrs r2, psplim /* r2 = PSPLIM. */
\r
239 mrs r3, control /* r3 = CONTROL. */
\r
240 mov r4, lr /* r4 = LR/EXC_RETURN. */
\r
241 subs r1, r1, #48 /* r1 = r1 - 48. */
\r
242 stmia r1!, {r0, r2-r4} /* Store xSecureContext, PSPLIM, CONTROL and LR on the stack. */
\r
243 #else /* configENABLE_MPU */
\r
244 subs r1, r1, #44 /* Make space for xSecureContext, PSPLIM, LR and the remaining registers on the stack. */
\r
245 str r1, [r2] /* Save the new top of stack in TCB. */
\r
246 mrs r2, psplim /* r2 = PSPLIM. */
\r
247 mov r3, lr /* r3 = LR/EXC_RETURN. */
\r
248 stmia r1!, {r0, r2-r7} /* Store xSecureContext, PSPLIM, LR and the low registers that are not saved automatically. */
\r
249 mov r4, r8 /* r4 = r8. */
\r
250 mov r5, r9 /* r5 = r9. */
\r
251 mov r6, r10 /* r6 = r10. */
\r
252 mov r7, r11 /* r7 = r11. */
\r
253 stmia r1!, {r4-r7} /* Store the high registers that are not saved automatically. */
\r
254 #endif /* configENABLE_MPU */
\r
258 bl vTaskSwitchContext
\r
261 ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
\r
262 ldr r3, [r2] /* Read pxCurrentTCB. */
\r
263 ldr r1, [r3] /* The first item in pxCurrentTCB is the task top of stack. r1 now points to the top of stack. */
\r
265 #if ( configENABLE_MPU == 1 )
\r
266 dmb /* Complete outstanding transfers before disabling MPU. */
\r
267 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
268 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
269 movs r5, #1 /* r5 = 1. */
\r
270 bics r4, r5 /* r4 = r4 & ~r5 i.e. Clear the bit 0 in r4. */
\r
271 str r4, [r2] /* Disable MPU. */
\r
273 adds r3, #4 /* r3 = r3 + 4. r3 now points to MAIR0 in TCB. */
\r
274 ldr r4, [r3] /* r4 = *r3 i.e. r4 = MAIR0. */
\r
275 ldr r2, =0xe000edc0 /* r2 = 0xe000edc0 [Location of MAIR0]. */
\r
276 str r4, [r2] /* Program MAIR0. */
\r
277 ldr r2, =0xe000ed98 /* r2 = 0xe000ed98 [Location of RNR]. */
\r
278 adds r3, #4 /* r3 = r3 + 4. r3 now points to first RBAR in TCB. */
\r
279 movs r5, #4 /* r5 = 4. */
\r
280 str r5, [r2] /* Program RNR = 4. */
\r
281 ldmia r3!, {r6,r7} /* Read first set of RBAR/RLAR from TCB. */
\r
282 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
283 stmia r4!, {r6,r7} /* Write first set of RBAR/RLAR registers. */
\r
284 movs r5, #5 /* r5 = 5. */
\r
285 str r5, [r2] /* Program RNR = 5. */
\r
286 ldmia r3!, {r6,r7} /* Read second set of RBAR/RLAR from TCB. */
\r
287 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
288 stmia r4!, {r6,r7} /* Write second set of RBAR/RLAR registers. */
\r
289 movs r5, #6 /* r5 = 6. */
\r
290 str r5, [r2] /* Program RNR = 6. */
\r
291 ldmia r3!, {r6,r7} /* Read third set of RBAR/RLAR from TCB. */
\r
292 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
293 stmia r4!, {r6,r7} /* Write third set of RBAR/RLAR registers. */
\r
294 movs r5, #7 /* r5 = 7. */
\r
295 str r5, [r2] /* Program RNR = 7. */
\r
296 ldmia r3!, {r6,r7} /* Read fourth set of RBAR/RLAR from TCB. */
\r
297 ldr r4, =0xe000ed9c /* r4 = 0xe000ed9c [Location of RBAR]. */
\r
298 stmia r4!, {r6,r7} /* Write fourth set of RBAR/RLAR registers. */
\r
300 ldr r2, =0xe000ed94 /* r2 = 0xe000ed94 [Location of MPU_CTRL]. */
\r
301 ldr r4, [r2] /* Read the value of MPU_CTRL. */
\r
302 movs r5, #1 /* r5 = 1. */
\r
303 orrs r4, r5 /* r4 = r4 | r5 i.e. Set the bit 0 in r4. */
\r
304 str r4, [r2] /* Enable MPU. */
\r
305 dsb /* Force memory writes before continuing. */
\r
306 #endif /* configENABLE_MPU */
\r
308 #if ( configENABLE_MPU == 1 )
\r
309 ldmia r1!, {r0, r2-r4} /* Read from stack - r0 = xSecureContext, r2 = PSPLIM, r3 = CONTROL and r4 = LR. */
\r
310 msr psplim, r2 /* Restore the PSPLIM register value for the task. */
\r
311 msr control, r3 /* Restore the CONTROL register value for the task. */
\r
312 mov lr, r4 /* LR = r4. */
\r
313 ldr r2, =xSecureContext /* Read the location of xSecureContext i.e. &( xSecureContext ). */
\r
314 str r0, [r2] /* Restore the task's xSecureContext. */
\r
315 cbz r0, restore_ns_context /* If there is no secure context for the task, restore the non-secure context. */
\r
317 bl SecureContext_LoadContext /* Restore the secure context. */
\r
319 mov lr, r4 /* LR = r4. */
\r
320 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
321 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
322 msr psp, r1 /* Remember the new top of stack for the task. */
\r
324 #else /* configENABLE_MPU */
\r
325 ldmia r1!, {r0, r2-r3} /* Read from stack - r0 = xSecureContext, r2 = PSPLIM and r3 = LR. */
\r
326 msr psplim, r2 /* Restore the PSPLIM register value for the task. */
\r
327 mov lr, r3 /* LR = r3. */
\r
328 ldr r2, =xSecureContext /* Read the location of xSecureContext i.e. &( xSecureContext ). */
\r
329 str r0, [r2] /* Restore the task's xSecureContext. */
\r
330 cbz r0, restore_ns_context /* If there is no secure context for the task, restore the non-secure context. */
\r
332 bl SecureContext_LoadContext /* Restore the secure context. */
\r
334 mov lr, r3 /* LR = r3. */
\r
335 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
336 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
337 msr psp, r1 /* Remember the new top of stack for the task. */
\r
339 #endif /* configENABLE_MPU */
\r
341 restore_ns_context:
\r
342 adds r1, r1, #16 /* Move to the high registers. */
\r
343 ldmia r1!, {r4-r7} /* Restore the high registers that are not automatically restored. */
\r
344 mov r8, r4 /* r8 = r4. */
\r
345 mov r9, r5 /* r9 = r5. */
\r
346 mov r10, r6 /* r10 = r6. */
\r
347 mov r11, r7 /* r11 = r7. */
\r
348 msr psp, r1 /* Remember the new top of stack for the task. */
\r
349 subs r1, r1, #32 /* Go back to the low registers. */
\r
350 ldmia r1!, {r4-r7} /* Restore the low registers that are not automatically restored. */
\r
352 /*-----------------------------------------------------------*/
\r
358 beq stacking_used_msp
\r
360 b vPortSVCHandler_C
\r
363 b vPortSVCHandler_C
\r
364 /*-----------------------------------------------------------*/
\r
366 vPortFreeSecureContext:
\r
367 ldr r1, [r0] /* The first item in the TCB is the top of the stack. */
\r
368 ldr r0, [r1] /* The first item on the stack is the task's xSecureContext. */
\r
369 cmp r0, #0 /* Raise svc if task's xSecureContext is not NULL. */
\r
370 beq free_secure_context
\r
371 bx lr /* There is no secure context (xSecureContext is NULL). */
\r
372 free_secure_context:
\r
373 svc 1 /* Secure context is freed in the supervisor call. portSVC_FREE_SECURE_CONTEXT = 1. */
\r
374 bx lr /* Return. */
\r
375 /*-----------------------------------------------------------*/
\r