]> begriffs open source - freertos/blob - portable/IAR/ARM_CM55_NTZ/non_secure/portasm.s
Armv8.1-m: Add pacbti support (#1147)
[freertos] / portable / IAR / ARM_CM55_NTZ / non_secure / portasm.s
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
31 contains code not understood by the assembler - for example the 'extern' keyword.
32 To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so
33 the code is included in C files but excluded by the preprocessor in assembly
34 files (__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 vTaskSwitchContext
46     EXTERN vPortSVCHandler_C
47 #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
48     EXTERN vSystemCallEnter
49     EXTERN vSystemCallExit
50 #endif
51
52     PUBLIC xIsPrivileged
53     PUBLIC vResetPrivilege
54     PUBLIC vRestoreContextOfFirstTask
55     PUBLIC vRaisePrivilege
56     PUBLIC vStartFirstTask
57     PUBLIC ulSetInterruptMask
58     PUBLIC vClearInterruptMask
59     PUBLIC PendSV_Handler
60     PUBLIC SVC_Handler
61 /*-----------------------------------------------------------*/
62
63 /*---------------- Unprivileged Functions -------------------*/
64
65 /*-----------------------------------------------------------*/
66
67     SECTION .text:CODE:NOROOT(2)
68     THUMB
69 /*-----------------------------------------------------------*/
70
71 xIsPrivileged:
72     mrs r0, control                         /* r0 = CONTROL. */
73     tst r0, #1                              /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
74     ite ne
75     movne r0, #0                            /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
76     moveq r0, #1                            /* CONTROL[0]==0. Return true to indicate that the processor is not privileged. */
77     bx lr                                   /* Return. */
78 /*-----------------------------------------------------------*/
79
80 vResetPrivilege:
81     mrs r0, control                         /* r0 = CONTROL. */
82     orr r0, r0, #1                          /* r0 = r0 | 1. */
83     msr control, r0                         /* CONTROL = r0. */
84     bx lr                                   /* Return to the caller. */
85 /*-----------------------------------------------------------*/
86
87 /*----------------- Privileged Functions --------------------*/
88
89 /*-----------------------------------------------------------*/
90
91     SECTION privileged_functions:CODE:NOROOT(2)
92     THUMB
93 /*-----------------------------------------------------------*/
94
95 #if ( configENABLE_MPU == 1 )
96
97 vRestoreContextOfFirstTask:
98     program_mpu_first_task:
99         ldr r2, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
100         ldr r0, [r2]                        /* r0 = pxCurrentTCB. */
101
102         dmb                                 /* Complete outstanding transfers before disabling MPU. */
103         ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
104         ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
105         bic r2, #1                          /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
106         str r2, [r1]                        /* Disable MPU. */
107
108         adds r0, #4                         /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
109         ldr r1, [r0]                        /* r1 = *r0 i.e. r1 = MAIR0. */
110         ldr r2, =0xe000edc0                 /* r2 = 0xe000edc0 [Location of MAIR0]. */
111         str r1, [r2]                        /* Program MAIR0. */
112
113         adds r0, #4                         /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
114         ldr r1, =0xe000ed98                 /* r1 = 0xe000ed98 [Location of RNR]. */
115         ldr r2, =0xe000ed9c                 /* r2 = 0xe000ed9c [Location of RBAR]. */
116
117         movs r3, #4                         /* r3 = 4. */
118         str r3, [r1]                        /* Program RNR = 4. */
119         ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
120         stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
121
122     #if ( configTOTAL_MPU_REGIONS == 16 )
123         movs r3, #8                         /* r3 = 8. */
124         str r3, [r1]                        /* Program RNR = 8. */
125         ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
126         stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
127         movs r3, #12                        /* r3 = 12. */
128         str r3, [r1]                        /* Program RNR = 12. */
129         ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
130         stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
131     #endif /* configTOTAL_MPU_REGIONS == 16 */
132
133         ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
134         ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
135         orr r2, #1                          /* r2 = r2 | 1 i.e. Set the bit 0 in r2. */
136         str r2, [r1]                        /* Enable MPU. */
137         dsb                                 /* Force memory writes before continuing. */
138
139     restore_context_first_task:
140         ldr r2, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
141         ldr r0, [r2]                        /* r0 = pxCurrentTCB.*/
142         ldr r1, [r0]                        /* r1 = Location of saved context in TCB. */
143
144     restore_special_regs_first_task:
145         ldmdb r1!, {r2-r4, lr}              /* r2 = original PSP, r3 = PSPLIM, r4 = CONTROL, LR restored. */
146         msr psp, r2
147         msr psplim, r3
148         msr control, r4
149
150     restore_general_regs_first_task:
151         ldmdb r1!, {r4-r11}                 /* r4-r11 contain hardware saved context. */
152         stmia r2!, {r4-r11}                 /* Copy the hardware saved context on the task stack. */
153         ldmdb r1!, {r4-r11}                 /* r4-r11 restored. */
154
155     restore_context_done_first_task:
156         str r1, [r0]                        /* Save the location where the context should be saved next as the first member of TCB. */
157         mov r0, #0
158         msr basepri, r0                     /* Ensure that interrupts are enabled when the first task starts. */
159         bx lr
160
161 #else /* configENABLE_MPU */
162
163 vRestoreContextOfFirstTask:
164     ldr  r2, =pxCurrentTCB                  /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
165     ldr  r1, [r2]                           /* Read pxCurrentTCB. */
166     ldr  r0, [r1]                           /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
167
168     ldm  r0!, {r1-r2}                       /* Read from stack - r1 = PSPLIM and r2 = EXC_RETURN. */
169     msr  psplim, r1                         /* Set this task's PSPLIM value. */
170     mrs  r1, control                        /* Obtain current control register value. */
171     orrs r1, r1, #2                         /* r1 = r1 | 0x2 - Set the second bit to use the program stack pointe (PSP). */
172     msr control, r1                         /* Write back the new control register value. */
173     adds r0, #32                            /* Discard everything up to r0. */
174     msr  psp, r0                            /* This is now the new top of stack to use in the task. */
175     isb
176     mov  r0, #0
177     msr  basepri, r0                        /* Ensure that interrupts are enabled when the first task starts. */
178     bx   r2                                 /* Finally, branch to EXC_RETURN. */
179
180 #endif /* configENABLE_MPU */
181 /*-----------------------------------------------------------*/
182
183 vRaisePrivilege:
184     mrs  r0, control                        /* Read the CONTROL register. */
185     bic r0, r0, #1                          /* Clear the bit 0. */
186     msr  control, r0                        /* Write back the new CONTROL value. */
187     bx lr                                   /* Return to the caller. */
188 /*-----------------------------------------------------------*/
189
190 vStartFirstTask:
191     ldr r0, =0xe000ed08                     /* Use the NVIC offset register to locate the stack. */
192     ldr r0, [r0]                            /* Read the VTOR register which gives the address of vector table. */
193     ldr r0, [r0]                            /* The first entry in vector table is stack pointer. */
194     msr msp, r0                             /* Set the MSP back to the start of the stack. */
195     cpsie i                                 /* Globally enable interrupts. */
196     cpsie f
197     dsb
198     isb
199     svc 102                                 /* System call to start the first task. portSVC_START_SCHEDULER = 102. */
200 /*-----------------------------------------------------------*/
201
202 ulSetInterruptMask:
203     mrs r0, basepri                         /* r0 = basepri. Return original basepri value. */
204     mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
205     msr basepri, r1                         /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
206     dsb
207     isb
208     bx lr                                   /* Return. */
209 /*-----------------------------------------------------------*/
210
211 vClearInterruptMask:
212     msr basepri, r0                         /* basepri = ulMask. */
213     dsb
214     isb
215     bx lr                                   /* Return. */
216 /*-----------------------------------------------------------*/
217
218 #if ( configENABLE_MPU == 1 )
219
220 PendSV_Handler:
221     ldr r2, =pxCurrentTCB                   /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
222     ldr r0, [r2]                            /* r0 = pxCurrentTCB. */
223     ldr r1, [r0]                            /* r1 = Location in TCB where the context should be saved. */
224     mrs r2, psp                             /* r2 = PSP. */
225
226     save_general_regs:
227     #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
228         add r2, r2, #0x20                   /* Move r2 to location where s0 is saved. */
229         tst lr, #0x10
230         ittt eq
231         vstmiaeq r1!, {s16-s31}             /* Store s16-s31. */
232         vldmiaeq r2, {s0-s16}               /* Copy hardware saved FP context into s0-s16. */
233         vstmiaeq r1!, {s0-s16}              /* Store hardware saved FP context. */
234         sub r2, r2, #0x20                   /* Set r2 back to the location of hardware saved context. */
235     #endif /* configENABLE_FPU || configENABLE_MVE */
236
237         stmia r1!, {r4-r11}                 /* Store r4-r11. */
238         ldmia r2, {r4-r11}                  /* Copy the hardware saved context into r4-r11. */
239         stmia r1!, {r4-r11}                 /* Store the hardware saved context. */
240
241     save_special_regs:
242         mrs r3, psplim                      /* r3 = PSPLIM. */
243         mrs r4, control                     /* r4 = CONTROL. */
244         stmia r1!, {r2-r4, lr}              /* Store original PSP (after hardware has saved context), PSPLIM, CONTROL and LR. */
245         str r1, [r0]                        /* Save the location from where the context should be restored as the first member of TCB. */
246
247     select_next_task:
248         mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
249         msr basepri, r0                     /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
250         dsb
251         isb
252         bl vTaskSwitchContext
253         mov r0, #0                          /* r0 = 0. */
254         msr basepri, r0                     /* Enable interrupts. */
255
256     program_mpu:
257         ldr r2, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
258         ldr r0, [r2]                        /* r0 = pxCurrentTCB. */
259
260         dmb                                 /* Complete outstanding transfers before disabling MPU. */
261         ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
262         ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
263         bic r2, #1                          /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
264         str r2, [r1]                        /* Disable MPU. */
265
266         adds r0, #4                         /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
267         ldr r1, [r0]                        /* r1 = *r0 i.e. r1 = MAIR0. */
268         ldr r2, =0xe000edc0                 /* r2 = 0xe000edc0 [Location of MAIR0]. */
269         str r1, [r2]                        /* Program MAIR0. */
270
271         adds r0, #4                         /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
272         ldr r1, =0xe000ed98                 /* r1 = 0xe000ed98 [Location of RNR]. */
273         ldr r2, =0xe000ed9c                 /* r2 = 0xe000ed9c [Location of RBAR]. */
274
275         movs r3, #4                         /* r3 = 4. */
276         str r3, [r1]                        /* Program RNR = 4. */
277         ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
278         stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
279
280     #if ( configTOTAL_MPU_REGIONS == 16 )
281         movs r3, #8                         /* r3 = 8. */
282         str r3, [r1]                        /* Program RNR = 8. */
283         ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
284         stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
285         movs r3, #12                        /* r3 = 12. */
286         str r3, [r1]                        /* Program RNR = 12. */
287         ldmia r0!, {r4-r11}                 /* Read 4 sets of RBAR/RLAR registers from TCB. */
288         stmia r2, {r4-r11}                  /* Write 4 set of RBAR/RLAR registers using alias registers. */
289     #endif /* configTOTAL_MPU_REGIONS == 16 */
290
291         ldr r1, =0xe000ed94                 /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
292         ldr r2, [r1]                        /* Read the value of MPU_CTRL. */
293         orr r2, #1                          /* r2 = r2 | 1 i.e. Set the bit 0 in r2. */
294         str r2, [r1]                        /* Enable MPU. */
295         dsb                                 /* Force memory writes before continuing. */
296
297     restore_context:
298         ldr r2, =pxCurrentTCB               /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
299         ldr r0, [r2]                        /* r0 = pxCurrentTCB.*/
300         ldr r1, [r0]                        /* r1 = Location of saved context in TCB. */
301
302     restore_special_regs:
303         ldmdb r1!, {r2-r4, lr}              /* r2 = original PSP, r3 = PSPLIM, r4 = CONTROL, LR restored. */
304         msr psp, r2
305         msr psplim, r3
306         msr control, r4
307
308     restore_general_regs:
309         ldmdb r1!, {r4-r11}                 /* r4-r11 contain hardware saved context. */
310         stmia r2!, {r4-r11}                 /* Copy the hardware saved context on the task stack. */
311         ldmdb r1!, {r4-r11}                 /* r4-r11 restored. */
312     #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
313         tst lr, #0x10
314         ittt eq
315         vldmdbeq r1!, {s0-s16}              /* s0-s16 contain hardware saved FP context. */
316         vstmiaeq r2!, {s0-s16}              /* Copy hardware saved FP context on the task stack. */
317         vldmdbeq r1!, {s16-s31}             /* Restore s16-s31. */
318     #endif /* configENABLE_FPU || configENABLE_MVE */
319
320     restore_context_done:
321         str r1, [r0]                        /* Save the location where the context should be saved next as the first member of TCB. */
322         bx lr
323
324 #else /* configENABLE_MPU */
325
326 PendSV_Handler:
327     mrs r0, psp                             /* Read PSP in r0. */
328 #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
329     tst lr, #0x10                           /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the Extended Stack Frame is in use. */
330     it eq
331     vstmdbeq r0!, {s16-s31}                 /* Store the additional FP context registers which are not saved automatically. */
332 #endif /* configENABLE_FPU || configENABLE_MVE */
333
334     mrs r2, psplim                          /* r2 = PSPLIM. */
335     mov r3, lr                              /* r3 = LR/EXC_RETURN. */
336     stmdb r0!, {r2-r11}                     /* Store on the stack - PSPLIM, LR and registers that are not automatically. */
337
338     ldr r2, =pxCurrentTCB                   /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
339     ldr r1, [r2]                            /* Read pxCurrentTCB. */
340     str r0, [r1]                            /* Save the new top of stack in TCB. */
341
342     mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
343     msr basepri, r0                         /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
344     dsb
345     isb
346     bl vTaskSwitchContext
347     mov r0, #0                              /* r0 = 0. */
348     msr basepri, r0                         /* Enable interrupts. */
349
350     ldr r2, =pxCurrentTCB                   /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
351     ldr r1, [r2]                            /* Read pxCurrentTCB. */
352     ldr r0, [r1]                            /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
353
354     ldmia r0!, {r2-r11}                     /* Read from stack - r2 = PSPLIM, r3 = LR and r4-r11 restored. */
355
356 #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
357     tst r3, #0x10                           /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the Extended Stack Frame is in use. */
358     it eq
359     vldmiaeq r0!, {s16-s31}                 /* Restore the additional FP context registers which are not restored automatically. */
360 #endif /* configENABLE_FPU || configENABLE_MVE */
361
362     msr psplim, r2                          /* Restore the PSPLIM register value for the task. */
363     msr psp, r0                             /* Remember the new top of stack for the task. */
364     bx r3
365
366 #endif /* configENABLE_MPU */
367 /*-----------------------------------------------------------*/
368
369 #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
370
371 SVC_Handler:
372     tst lr, #4
373     ite eq
374     mrseq r0, msp
375     mrsne r0, psp
376
377     ldr r1, [r0, #24]
378     ldrb r2, [r1, #-2]
379     cmp r2, #NUM_SYSTEM_CALLS
380     blt syscall_enter
381     cmp r2, #104            /* portSVC_SYSTEM_CALL_EXIT. */
382     beq syscall_exit
383     b vPortSVCHandler_C
384
385     syscall_enter:
386         mov r1, lr
387         b vSystemCallEnter
388
389     syscall_exit:
390         mov r1, lr
391         b vSystemCallExit
392
393 #else /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
394
395 SVC_Handler:
396     tst lr, #4
397     ite eq
398     mrseq r0, msp
399     mrsne r0, psp
400     b vPortSVCHandler_C
401
402 #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
403 /*-----------------------------------------------------------*/
404
405     END