1/*
2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 * Copyright 2024 Arm Limited and/or its affiliates
5 * <open-source-office@arm.com>
6 *
7 * SPDX-License-Identifier: MIT
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10 * this software and associated documentation files (the "Software"), to deal in
11 * the Software without restriction, including without limitation the rights to
12 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13 * the Software, and to permit persons to whom the Software is furnished to do so,
14 * subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * https://www.FreeRTOS.org
27 * https://github.com/FreeRTOS
28 *
29 */
30/* Including FreeRTOSConfig.h here will cause build errors if the header file
31contains code not understood by the assembler - for example the 'extern' keyword.
32To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so
33the code is included in C files but excluded by the preprocessor in assembly
34files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler. */
35#include "FreeRTOSConfig.h"
36
37/* System call numbers includes. */
38#include "mpu_syscall_numbers.h"
39
40#ifndef configUSE_MPU_WRAPPERS_V1
41    #define configUSE_MPU_WRAPPERS_V1 0
42#endif
43
44    EXTERN pxCurrentTCB
45    EXTERN xSecureContext
46    EXTERN vTaskSwitchContext
47    EXTERN vPortSVCHandler_C
48    EXTERN SecureContext_SaveContext
49    EXTERN SecureContext_LoadContext
50#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
51    EXTERN vSystemCallEnter
52    EXTERN vSystemCallExit
53#endif
54
55    PUBLIC xIsPrivileged
56    PUBLIC vResetPrivilege
57    PUBLIC vPortAllocateSecureContext
58    PUBLIC vRestoreContextOfFirstTask
59    PUBLIC vRaisePrivilege
60    PUBLIC vStartFirstTask
61    PUBLIC ulSetInterruptMask
62    PUBLIC vClearInterruptMask
63    PUBLIC PendSV_Handler
64    PUBLIC SVC_Handler
65    PUBLIC vPortFreeSecureContext
66/*-----------------------------------------------------------*/
67
68/*---------------- Unprivileged Functions -------------------*/
69
70/*-----------------------------------------------------------*/
71
72    SECTION .text:CODE:NOROOT(2)
73    THUMB
74/*-----------------------------------------------------------*/
75
76xIsPrivileged:
77    mrs r0, control                         /* r0 = CONTROL. */
78    tst r0, #1                              /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
79    ite ne
80    movne r0, #0                            /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
81    moveq r0, #1                            /* CONTROL[0]==0. Return true to indicate that the processor is not privileged. */
82    bx lr                                   /* Return. */
83/*-----------------------------------------------------------*/
84
85vResetPrivilege:
86    mrs r0, control                         /* r0 = CONTROL. */
87    orr r0, r0, #1                          /* r0 = r0 | 1. */
88    msr control, r0                         /* CONTROL = r0. */
89    bx lr                                   /* Return to the caller. */
90/*-----------------------------------------------------------*/
91
92vPortAllocateSecureContext:
93    svc 100                                 /* Secure context is allocated in the supervisor call. portSVC_ALLOCATE_SECURE_CONTEXT = 100. */
94    bx lr                                   /* Return. */
95/*-----------------------------------------------------------*/
96
97/*----------------- Privileged Functions --------------------*/
98
99/*-----------------------------------------------------------*/
100
101    SECTION privileged_functions:CODE:NOROOT(2)
102    THUMB
103/*-----------------------------------------------------------*/
104
105#if ( configENABLE_MPU == 1 )
106
107vRestoreContextOfFirstTask:
108    program_mpu_first_task:
109        ldr r3, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
110        ldr r0, [r3]                        /* r0 = pxCurrentTCB. */
111
112        dmb                                 /* Complete outstanding transfers before disabling MPU. */
113        ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
114        ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
115        bic r2, #1                          /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
116        str r2, [r1]                        /* Disable MPU. */
117
118        adds r0, #4                         /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
119        ldr r1, [r0]                        /* r1 = *r0 i.e. r1 = MAIR0. */
120        ldr r2, =0xe000edc0                 /* r2 = 0xe000edc0 [Location of MAIR0]. */
121        str r1, [r2]                        /* Program MAIR0. */
122
123        adds r0, #4                         /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
124        ldr r1, =0xe000ed98                 /* r1 = 0xe000ed98 [Location of RNR]. */
125        ldr r2, =0xe000ed9c                 /* r2 = 0xe000ed9c [Location of RBAR]. */
126
127        movs r3, #4                         /* r3 = 4. */
128        str r3, [r1]                        /* Program RNR = 4. */
129        ldmia r0!, {r4-r11}                 /* Read 4 set of RBAR/RLAR registers from TCB. */
130        stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
131
132    #if ( configTOTAL_MPU_REGIONS == 16 )
133        movs r3, #8                         /* r3 = 8. */
134        str r3, [r1]                        /* Program RNR = 8. */
135        ldmia r0!, {r4-r11}                 /* Read 4 set of RBAR/RLAR registers from TCB. */
136        stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
137        movs r3, #12                        /* r3 = 12. */
138        str r3, [r1]                        /* Program RNR = 12. */
139        ldmia r0!, {r4-r11}                 /* Read 4 set of RBAR/RLAR registers from TCB. */
140        stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
141    #endif /* configTOTAL_MPU_REGIONS == 16 */
142
143        ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
144        ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
145        orr r2, #1                          /* r2 = r1 | 1 i.e. Set the bit 0 in r2. */
146        str r2, [r1]                        /* Enable MPU. */
147        dsb                                 /* Force memory writes before continuing. */
148
149    restore_context_first_task:
150        ldr r3, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
151        ldr r1, [r3]                        /* r1 = pxCurrentTCB.*/
152        ldr r2, [r1]                        /* r2 = Location of saved context in TCB. */
153
154    restore_special_regs_first_task:
155    #if ( configENABLE_PAC == 1 )
156        ldmdb r2!, {r3-r6}                  /* Read task's dedicated PAC key from the task's context. */
157        msr  PAC_KEY_P_0, r3                /* Write the task's dedicated PAC key to the PAC key registers. */
158        msr  PAC_KEY_P_1, r4
159        msr  PAC_KEY_P_2, r5
160        msr  PAC_KEY_P_3, r6
161        clrm {r3-r6}                        /* Clear r3-r6. */
162    #endif /* configENABLE_PAC */
163        ldmdb r2!, {r0, r3-r5, lr}          /* r0 = xSecureContext, r3 = original PSP, r4 = PSPLIM, r5 = CONTROL, LR restored. */
164        msr psp, r3
165        msr psplim, r4
166        msr control, r5
167        ldr r4, =xSecureContext             /* Read the location of xSecureContext i.e. &( xSecureContext ). */
168        str r0, [r4]                        /* Restore xSecureContext. */
169
170    restore_general_regs_first_task:
171        ldmdb r2!, {r4-r11}                 /* r4-r11 contain hardware saved context. */
172        stmia r3!, {r4-r11}                 /* Copy the hardware saved context on the task stack. */
173        ldmdb r2!, {r4-r11}                 /* r4-r11 restored. */
174
175    restore_context_done_first_task:
176        str r2, [r1]                        /* Save the location where the context should be saved next as the first member of TCB. */
177        mov r0, #0
178        msr basepri, r0                     /* Ensure that interrupts are enabled when the first task starts. */
179        bx lr
180
181#else /* configENABLE_MPU */
182
183vRestoreContextOfFirstTask:
184    ldr  r2, =pxCurrentTCB                  /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
185    ldr  r3, [r2]                           /* Read pxCurrentTCB. */
186    ldr  r0, [r3]                           /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
187
188#if ( configENABLE_PAC == 1 )
189    ldmia r0!, {r1-r4}                      /* Read task's dedicated PAC key from stack. */
190    msr  PAC_KEY_P_3, r1                    /* Write the task's dedicated PAC key to the PAC key registers. */
191    msr  PAC_KEY_P_2, r2
192    msr  PAC_KEY_P_1, r3
193    msr  PAC_KEY_P_0, r4
194    clrm {r1-r4}                            /* Clear r1-r4.  */
195#endif /* configENABLE_PAC */
196
197    ldm  r0!, {r1-r3}                       /* Read from stack - r1 = xSecureContext, r2 = PSPLIM and r3 = EXC_RETURN. */
198    ldr  r4, =xSecureContext
199    str  r1, [r4]                           /* Set xSecureContext to this task's value for the same. */
200    msr  psplim, r2                         /* Set this task's PSPLIM value. */
201    mrs  r1, control                        /* Obtain current control register value. */
202    orrs r1, r1, #2                         /* r1 = r1 | 0x2 - Set the second bit to use the program stack pointe (PSP). */
203    msr control, r1                         /* Write back the new control register value. */
204    adds r0, #32                            /* Discard everything up to r0. */
205    msr  psp, r0                            /* This is now the new top of stack to use in the task. */
206    isb
207    mov  r0, #0
208    msr  basepri, r0                        /* Ensure that interrupts are enabled when the first task starts. */
209    bx   r3                                 /* Finally, branch to EXC_RETURN. */
210
211#endif /* configENABLE_MPU */
212/*-----------------------------------------------------------*/
213
214vRaisePrivilege:
215    mrs  r0, control                        /* Read the CONTROL register. */
216    bic r0, r0, #1                          /* Clear the bit 0. */
217    msr  control, r0                        /* Write back the new CONTROL value. */
218    bx lr                                   /* Return to the caller. */
219/*-----------------------------------------------------------*/
220
221vStartFirstTask:
222    ldr r0, =0xe000ed08                     /* Use the NVIC offset register to locate the stack. */
223    ldr r0, [r0]                            /* Read the VTOR register which gives the address of vector table. */
224    ldr r0, [r0]                            /* The first entry in vector table is stack pointer. */
225    msr msp, r0                             /* Set the MSP back to the start of the stack. */
226    cpsie i                                 /* Globally enable interrupts. */
227    cpsie f
228    dsb
229    isb
230    svc 102                                 /* System call to start the first task. portSVC_START_SCHEDULER = 102. */
231/*-----------------------------------------------------------*/
232
233ulSetInterruptMask:
234    mrs r0, basepri                         /* r0 = basepri. Return original basepri value. */
235    mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
236    msr basepri, r1                         /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
237    dsb
238    isb
239    bx lr                                   /* Return. */
240/*-----------------------------------------------------------*/
241
242vClearInterruptMask:
243    msr basepri, r0                         /* basepri = ulMask. */
244    dsb
245    isb
246    bx lr                                   /* Return. */
247/*-----------------------------------------------------------*/
248
249#if ( configENABLE_MPU == 1 )
250
251PendSV_Handler:
252    ldr r3, =xSecureContext                 /* Read the location of xSecureContext i.e. &( xSecureContext ). */
253    ldr r0, [r3]                            /* Read xSecureContext - Value of xSecureContext must be in r0 as it is used as a parameter later. */
254    ldr r3, =pxCurrentTCB                   /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
255    ldr r1, [r3]                            /* Read pxCurrentTCB - Value of pxCurrentTCB must be in r1 as it is used as a parameter later. */
256    ldr r2, [r1]                            /* r2 = Location in TCB where the context should be saved. */
257
258    cbz r0, save_ns_context                 /* No secure context to save. */
259    save_s_context:
260        push {r0-r2, lr}
261        bl SecureContext_SaveContext        /* Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
262        pop {r0-r2, lr}
263
264    save_ns_context:
265        mov r3, lr                          /* r3 = LR (EXC_RETURN). */
266        lsls r3, r3, #25                    /* r3 = 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. */
267        bmi save_special_regs               /* r3 < 0 ==> Bit[6] in EXC_RETURN is 1 ==> secure stack was used to store the stack frame. */
268
269    save_general_regs:
270        mrs r3, psp
271
272    #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
273        add r3, r3, #0x20                   /* Move r3 to location where s0 is saved. */
274        tst lr, #0x10
275        ittt eq
276        vstmiaeq r2!, {s16-s31}             /* Store s16-s31. */
277        vldmiaeq r3, {s0-s16}               /* Copy hardware saved FP context into s0-s16. */
278        vstmiaeq r2!, {s0-s16}              /* Store hardware saved FP context. */
279        sub r3, r3, #0x20                   /* Set r3 back to the location of hardware saved context. */
280    #endif /* configENABLE_FPU || configENABLE_MVE */
281
282        stmia r2!, {r4-r11}                 /* Store r4-r11. */
283        ldmia r3, {r4-r11}                  /* Copy the hardware saved context into r4-r11. */
284        stmia r2!, {r4-r11}                 /* Store the hardware saved context. */
285
286    save_special_regs:
287        mrs r3, psp                         /* r3 = PSP. */
288        mrs r4, psplim                      /* r4 = PSPLIM. */
289        mrs r5, control                     /* r5 = CONTROL. */
290        stmia r2!, {r0, r3-r5, lr}          /* Store xSecureContext, original PSP (after hardware has saved context), PSPLIM, CONTROL and LR. */
291    #if ( configENABLE_PAC == 1 )
292        mrs  r3, PAC_KEY_P_0                /* Read task's dedicated PAC key from the PAC key registers. */
293        mrs  r4, PAC_KEY_P_1
294        mrs  r5, PAC_KEY_P_2
295        mrs  r6, PAC_KEY_P_3
296        stmia r2!, {r3-r6}                  /* Store the task's dedicated PAC key on the task's context. */
297        clrm {r3-r6}                        /* Clear r3-r6. */
298    #endif /* configENABLE_PAC */
299
300    str r2, [r1]                            /* Save the location from where the context should be restored as the first member of TCB. */
301
302    select_next_task:
303        mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
304        msr basepri, r0                     /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
305        dsb
306        isb
307        bl vTaskSwitchContext
308        mov r0, #0                          /* r0 = 0. */
309        msr basepri, r0                     /* Enable interrupts. */
310
311    program_mpu:
312        ldr r3, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
313        ldr r0, [r3]                        /* r0 = pxCurrentTCB.*/
314
315        dmb                                 /* Complete outstanding transfers before disabling MPU. */
316        ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
317        ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
318        bic r2, #1                          /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
319        str r2, [r1]                        /* Disable MPU. */
320
321        adds r0, #4                         /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
322        ldr r1, [r0]                        /* r1 = *r0 i.e. r1 = MAIR0. */
323        ldr r2, =0xe000edc0                 /* r2 = 0xe000edc0 [Location of MAIR0]. */
324        str r1, [r2]                        /* Program MAIR0. */
325
326        adds r0, #4                         /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
327        ldr r1, =0xe000ed98                 /* r1 = 0xe000ed98 [Location of RNR]. */
328        ldr r2, =0xe000ed9c                 /* r2 = 0xe000ed9c [Location of RBAR]. */
329
330        movs r3, #4                         /* r3 = 4. */
331        str r3, [r1]                        /* Program RNR = 4. */
332        ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
333        stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
334
335    #if ( configTOTAL_MPU_REGIONS == 16 )
336        movs r3, #8                         /* r3 = 8. */
337        str r3, [r1]                        /* Program RNR = 8. */
338        ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
339        stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
340        movs r3, #12                        /* r3 = 12. */
341        str r3, [r1]                        /* Program RNR = 12. */
342        ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
343        stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
344    #endif /* configTOTAL_MPU_REGIONS == 16 */
345
346       ldr r1, =0xe000ed94                  /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
347       ldr r2, [r1]                         /* Read the value of MPU_CTRL. */
348       orr r2, #1                           /* r2 = r2 | 1 i.e. Set the bit 0 in r2. */
349       str r2, [r1]                         /* Enable MPU. */
350       dsb                                  /* Force memory writes before continuing. */
351
352    restore_context:
353        ldr r3, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
354        ldr r1, [r3]                        /* r1 = pxCurrentTCB.*/
355        ldr r2, [r1]                        /* r2 = Location of saved context in TCB. */
356
357    restore_special_regs:
358    #if ( configENABLE_PAC == 1 )
359        ldmdb r2!, {r3-r6}                  /* Read task's dedicated PAC key from the task's context. */
360        msr  PAC_KEY_P_0, r3                /* Write the task's dedicated PAC key to the PAC key registers. */
361        msr  PAC_KEY_P_1, r4
362        msr  PAC_KEY_P_2, r5
363        msr  PAC_KEY_P_3, r6
364        clrm {r3-r6}                        /* Clear r3-r6. */
365    #endif /* configENABLE_PAC */
366        ldmdb r2!, {r0, r3-r5, lr}          /* r0 = xSecureContext, r3 = original PSP, r4 = PSPLIM, r5 = CONTROL, LR restored. */
367        msr psp, r3
368        msr psplim, r4
369        msr control, r5
370        ldr r4, =xSecureContext             /* Read the location of xSecureContext i.e. &( xSecureContext ). */
371        str r0, [r4]                        /* Restore xSecureContext. */
372        cbz r0, restore_ns_context          /* No secure context to restore. */
373
374    restore_s_context:
375        push {r1-r3, lr}
376        bl SecureContext_LoadContext        /* Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
377        pop {r1-r3, lr}
378
379    restore_ns_context:
380        mov r0, lr                          /* r0 = LR (EXC_RETURN). */
381        lsls r0, r0, #25                    /* r0 = r0 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
382        bmi restore_context_done            /* r0 < 0 ==> Bit[6] in EXC_RETURN is 1 ==> secure stack was used to store the stack frame. */
383
384    restore_general_regs:
385        ldmdb r2!, {r4-r11}                 /* r4-r11 contain hardware saved context. */
386        stmia r3!, {r4-r11}                 /* Copy the hardware saved context on the task stack. */
387        ldmdb r2!, {r4-r11}                 /* r4-r11 restored. */
388
389    #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
390        tst lr, #0x10
391        ittt eq
392        vldmdbeq r2!, {s0-s16}              /* s0-s16 contain hardware saved FP context. */
393        vstmiaeq r3!, {s0-s16}              /* Copy hardware saved FP context on the task stack. */
394        vldmdbeq r2!, {s16-s31}             /* Restore s16-s31. */
395    #endif /* configENABLE_FPU || configENABLE_MVE */
396
397    restore_context_done:
398        str r2, [r1]                        /* Save the location where the context should be saved next as the first member of TCB. */
399        bx lr
400
401#else /* configENABLE_MPU */
402
403PendSV_Handler:
404    ldr r3, =xSecureContext                 /* Read the location of xSecureContext i.e. &( xSecureContext ). */
405    ldr r0, [r3]                            /* Read xSecureContext - Value of xSecureContext must be in r0 as it is used as a parameter later. */
406    ldr r3, =pxCurrentTCB                   /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
407    ldr r1, [r3]                            /* Read pxCurrentTCB - Value of pxCurrentTCB must be in r1 as it is used as a parameter later. */
408    mrs r2, psp                             /* Read PSP in r2. */
409
410    cbz r0, save_ns_context                 /* No secure context to save. */
411    save_s_context:
412        push {r0-r2, lr}
413        bl SecureContext_SaveContext       /* Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
414        pop {r0-r2, lr}
415
416    save_ns_context:
417        mov r3, lr                          /* r3 = LR. */
418        lsls r3, r3, #25                    /* r3 = 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. */
419        bmi save_special_regs               /* If r3 < 0 ==> Bit[6] in EXC_RETURN is 1 ==> secure stack was used. */
420
421    save_general_regs:
422    #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
423        tst lr, #0x10                       /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the Extended Stack Frame is in use. */
424        it eq
425        vstmdbeq r2!, {s16-s31}             /* Store the additional FP context registers which are not saved automatically. */
426    #endif /* configENABLE_FPU || configENABLE_MVE */
427        stmdb r2!, {r4-r11}                 /* Store the registers that are not saved automatically. */
428
429    save_special_regs:
430        mrs r3, psplim                      /* r3 = PSPLIM. */
431        stmdb r2!, {r0, r3, lr}             /* Store xSecureContext, PSPLIM and LR on the stack. */
432    #if ( configENABLE_PAC == 1 )
433        mrs  r3, PAC_KEY_P_3                /* Read task's dedicated PAC key from the PAC key registers. */
434        mrs  r4, PAC_KEY_P_2
435        mrs  r5, PAC_KEY_P_1
436        mrs  r6, PAC_KEY_P_0
437        stmdb r2!, {r3-r6}                  /* Store the task's dedicated PAC key on the stack. */
438        clrm {r3-r6}                        /* Clear r3-r6. */
439    #endif /* configENABLE_PAC */
440
441    str r2, [r1]                            /* Save the new top of stack in TCB. */
442
443    select_next_task:
444        mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
445        msr basepri, r0                     /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
446        dsb
447        isb
448        bl vTaskSwitchContext
449        mov r0, #0                          /* r0 = 0. */
450        msr basepri, r0                     /* Enable interrupts. */
451
452    restore_context:
453        ldr r3, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
454        ldr r1, [r3]                        /* Read pxCurrentTCB. */
455        ldr r2, [r1]                        /* The first item in pxCurrentTCB is the task top of stack. r2 now points to the top of stack. */
456
457    restore_special_regs:
458    #if ( configENABLE_PAC == 1 )
459        ldmia r2!, {r3-r6}                  /* Read task's dedicated PAC key from stack. */
460        msr  PAC_KEY_P_3, r3                /* Write the task's dedicated PAC key to the PAC key registers. */
461        msr  PAC_KEY_P_2, r4
462        msr  PAC_KEY_P_1, r5
463        msr  PAC_KEY_P_0, r6
464        clrm {r3-r6}                        /* Clear r3-r6. */
465    #endif /* configENABLE_PAC */
466        ldmia r2!, {r0, r3, lr}             http://files.iar.com/ftp/pub/box/bxarm-9.60.3.deb/* Read from stack - r0 = xSecureContext, r3 = PSPLIM and LR restored. */
467        msr psplim, r3                      /* Restore the PSPLIM register value for the task. */
468        ldr r3, =xSecureContext             /* Read the location of xSecureContext i.e. &( xSecureContext ). */
469        str r0, [r3]                        /* Restore the task's xSecureContext. */
470        cbz r0, restore_ns_context          /* If there is no secure context for the task, restore the non-secure context. */
471
472    restore_s_context:
473        push {r1-r3, lr}
474        bl SecureContext_LoadContext        /* Restore the secure context. Params are in r0 and r1. r0 = xSecureContext and r1 = pxCurrentTCB. */
475        pop {r1-r3, lr}
476
477    restore_ns_context:
478        mov r0, lr                          /* r0 = LR (EXC_RETURN). */
479        lsls r0, r0, #25                    /* r0 = r0 << 25. Bit[6] of EXC_RETURN is 1 if secure stack was used, 0 if non-secure stack was used to store stack frame. */
480        bmi restore_context_done            /* r0 < 0 ==> Bit[6] in EXC_RETURN is 1 ==> secure stack was used to store the stack frame. */
481
482    restore_general_regs:
483        ldmia r2!, {r4-r11}                 /* Restore the registers that are not automatically restored. */
484    #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
485        tst lr, #0x10                       /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the Extended Stack Frame is in use. */
486        it eq
487        vldmiaeq r2!, {s16-s31}             /* Restore the additional FP context registers which are not restored automatically. */
488    #endif /* configENABLE_FPU || configENABLE_MVE */
489
490    restore_context_done:
491        msr psp, r2                         /* Remember the new top of stack for the task. */
492        bx lr
493
494#endif /* configENABLE_MPU */
495/*-----------------------------------------------------------*/
496
497#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
498
499SVC_Handler:
500    tst lr, #4
501    ite eq
502    mrseq r0, msp
503    mrsne r0, psp
504
505    ldr r1, [r0, #24]
506    ldrb r2, [r1, #-2]
507    cmp r2, #NUM_SYSTEM_CALLS
508    blt syscall_enter
509    cmp r2, #104            /* portSVC_SYSTEM_CALL_EXIT. */
510    beq syscall_exit
511    b vPortSVCHandler_C
512
513    syscall_enter:
514        mov r1, lr
515        b vSystemCallEnter
516
517    syscall_exit:
518        mov r1, lr
519        b vSystemCallExit
520
521#else /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
522
523SVC_Handler:
524    tst lr, #4
525    ite eq
526    mrseq r0, msp
527    mrsne r0, psp
528    b vPortSVCHandler_C
529
530#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
531/*-----------------------------------------------------------*/
532
533vPortFreeSecureContext:
534    /* r0 = uint32_t *pulTCB. */
535    ldr r2, [r0]                            /* The first item in the TCB is the top of the stack. */
536    ldr r1, [r2]                            /* The first item on the stack is the task's xSecureContext. */
537    cmp r1, #0                              /* Raise svc if task's xSecureContext is not NULL. */
538    it ne
539    svcne 101                               /* Secure context is freed in the supervisor call. portSVC_FREE_SECURE_CONTEXT = 101. */
540    bx lr                                   /* Return. */
541/*-----------------------------------------------------------*/
542
543    END
544