]> begriffs open source - cmsis-freertos/blob - Source/portable/IAR/ARM_CM4F_MPU/portasm.s
Update FreeRTOS kernel to v11.2.0
[cmsis-freertos] / Source / portable / IAR / ARM_CM4F_MPU / portasm.s
1 /*
2  * FreeRTOS Kernel V11.2.0
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /* Including FreeRTOSConfig.h here will cause build errors if the header file
30 contains code not understood by the assembler - for example the 'extern' keyword.
31 To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so
32 the code is included in C files but excluded by the preprocessor in assembly
33 files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler. */
34 #include <FreeRTOSConfig.h>
35 #include <mpu_syscall_numbers.h>
36
37     RSEG    CODE:CODE(2)
38     thumb
39
40     EXTERN pxCurrentTCB
41     EXTERN vTaskSwitchContext
42     EXTERN vPortSVCHandler_C
43     EXTERN vSystemCallEnter
44     EXTERN vSystemCallExit
45
46     PUBLIC xPortPendSVHandler
47     PUBLIC vPortSVCHandler
48     PUBLIC vPortStartFirstTask
49     PUBLIC vPortEnableVFP
50     PUBLIC vPortRestoreContextOfFirstTask
51     PUBLIC xIsPrivileged
52     PUBLIC vResetPrivilege
53
54 /*-----------------------------------------------------------*/
55
56 #ifndef configUSE_MPU_WRAPPERS_V1
57     #define configUSE_MPU_WRAPPERS_V1 0
58 #endif
59
60 /* Errata 837070 workaround must be enabled on Cortex-M7 r0p0
61  * and r0p1 cores. */
62 #ifndef configENABLE_ERRATA_837070_WORKAROUND
63     #define configENABLE_ERRATA_837070_WORKAROUND 0
64 #endif
65
66 /* These must be in sync with portmacro.h. */
67 #define portSVC_START_SCHEDULER        100
68 #define portSVC_SYSTEM_CALL_EXIT       103
69 /*-----------------------------------------------------------*/
70
71 xPortPendSVHandler:
72
73     ldr r3, =pxCurrentTCB
74     ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
75     ldr r1, [r2]                           /* r1 = Location where the context should be saved. */
76
77     /*------------ Save Context. ----------- */
78     mrs r3, control
79     mrs r0, psp
80     isb
81
82     add r0, r0, #0x20                      /* Move r0 to location where s0 is saved. */
83     tst lr, #0x10
84     ittt eq
85     vstmiaeq r1!, {s16-s31}                /* Store s16-s31. */
86     vldmiaeq r0, {s0-s16}                  /* Copy hardware saved FP context into s0-s16. */
87     vstmiaeq r1!, {s0-s16}                 /* Store hardware saved FP context. */
88     sub r0, r0, #0x20                      /* Set r0 back to the location of hardware saved context. */
89
90     stmia r1!, {r3-r11, lr}                /* Store CONTROL register, r4-r11 and LR. */
91     ldmia r0, {r4-r11}                     /* Copy hardware saved context into r4-r11. */
92     stmia r1!, {r0, r4-r11}                /* Store original PSP (after hardware has saved context) and the hardware saved context. */
93     str r1, [r2]                           /* Save the location from where the context should be restored as the first member of TCB. */
94
95     /*---------- Select next task. --------- */
96     mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
97 #if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )
98     cpsid i                                /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */
99 #endif
100     msr basepri, r0
101     dsb
102     isb
103 #if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )
104     cpsie i                                /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */
105 #endif
106     bl vTaskSwitchContext
107     mov r0, #0
108     msr basepri, r0
109
110     /*------------ Program MPU. ------------ */
111     ldr r3, =pxCurrentTCB
112     ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
113     add r2, r2, #4                         /* r2 = Second item in the TCB which is xMPUSettings. */
114
115     dmb                                    /* Complete outstanding transfers before disabling MPU. */
116     ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
117     ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
118     bic r3, #1                             /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
119     str r3, [r0]                           /* Disable MPU. */
120
121     ldr r0, =0xe000ed9c                    /* Region Base Address register. */
122     ldmia r2!, {r4-r11}                    /* Read 4 sets of MPU registers [MPU Region # 0 - 3]. */
123     stmia r0, {r4-r11}                     /* Write 4 sets of MPU registers [MPU Region # 0 - 3]. */
124
125 #ifdef configTOTAL_MPU_REGIONS
126     #if ( configTOTAL_MPU_REGIONS == 16 )
127         ldmia r2!, {r4-r11}                 /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
128         stmia r0, {r4-r11}                  /* Write 4 sets of MPU registers. [MPU Region # 4 - 7]. */
129         ldmia r2!, {r4-r11}                 /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
130         stmia r0, {r4-r11}                  /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
131     #endif /* configTOTAL_MPU_REGIONS == 16. */
132 #endif
133
134     ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
135     ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
136     orr r3, #1                             /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
137     str r3, [r0]                           /* Enable MPU. */
138     dsb                                    /* Force memory writes before continuing. */
139
140     /*---------- Restore Context. ---------- */
141     ldr r3, =pxCurrentTCB
142     ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
143     ldr r1, [r2]                           /* r1 = Location of saved context in TCB. */
144
145     ldmdb r1!, {r0, r4-r11}                /* r0 contains PSP after the hardware had saved context. r4-r11 contain hardware saved context. */
146     msr psp, r0
147     stmia r0!, {r4-r11}                    /* Copy the hardware saved context on the task stack. */
148     ldmdb r1!, {r3-r11, lr}                /* r3 contains CONTROL register. r4-r11 and LR restored. */
149     msr control, r3
150
151     tst lr, #0x10
152     ittt eq
153     vldmdbeq r1!, {s0-s16}                 /* s0-s16 contain hardware saved FP context. */
154     vstmiaeq r0!, {s0-s16}                 /* Copy hardware saved FP context on the task stack. */
155     vldmdbeq r1!, {s16-s31}                /* Restore s16-s31. */
156
157     str r1, [r2]                           /* Save the location where the context should be saved next as the first member of TCB. */
158     bx lr
159
160 /*-----------------------------------------------------------*/
161
162 #if ( configUSE_MPU_WRAPPERS_V1 == 0 )
163
164 vPortSVCHandler:
165     tst lr, #4
166     ite eq
167     mrseq r0, msp
168     mrsne r0, psp
169
170     ldr r1, [r0, #24]
171     ldrb r2, [r1, #-2]
172     cmp r2, #NUM_SYSTEM_CALLS
173     blt syscall_enter
174     cmp r2, #portSVC_SYSTEM_CALL_EXIT
175     beq syscall_exit
176     b vPortSVCHandler_C
177
178     syscall_enter:
179         mov r1, lr
180         b vSystemCallEnter
181
182     syscall_exit:
183         mov r1, lr
184         b vSystemCallExit
185
186 #else /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
187
188 vPortSVCHandler:
189     #ifndef USE_PROCESS_STACK
190         tst lr, #4
191         ite eq
192         mrseq r0, msp
193         mrsne r0, psp
194     #else
195         mrs r0, psp
196     #endif
197         b vPortSVCHandler_C
198
199 #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
200 /*-----------------------------------------------------------*/
201
202 vPortStartFirstTask:
203     /* Use the NVIC offset register to locate the stack. */
204     ldr r0, =0xE000ED08
205     ldr r0, [r0]
206     ldr r0, [r0]
207     /* Set the msp back to the start of the stack. */
208     msr msp, r0
209     /* Clear the bit that indicates the FPU is in use in case the FPU was used
210     before the scheduler was started - which would otherwise result in the
211     unnecessary leaving of space in the SVC stack for lazy saving of FPU
212     registers. */
213     mov r0, #0
214     msr control, r0
215     /* Call SVC to start the first task. */
216     cpsie i
217     cpsie f
218     dsb
219     isb
220     svc #portSVC_START_SCHEDULER
221
222 /*-----------------------------------------------------------*/
223
224 vPortRestoreContextOfFirstTask:
225     ldr r0, =0xE000ED08                    /* Use the NVIC offset register to locate the stack. */
226     ldr r0, [r0]
227     ldr r0, [r0]
228     msr msp, r0                            /* Set the msp back to the start of the stack. */
229
230     /*------------ Program MPU. ------------ */
231     ldr r3, =pxCurrentTCB
232     ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
233     add r2, r2, #4                         /* r2 = Second item in the TCB which is xMPUSettings. */
234
235     dmb                                    /* Complete outstanding transfers before disabling MPU. */
236     ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
237     ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
238     bic r3, #1                             /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
239     str r3, [r0]                           /* Disable MPU. */
240
241     ldr r0, =0xe000ed9c                    /* Region Base Address register. */
242     ldmia r2!, {r4-r11}                    /* Read 4 sets of MPU registers [MPU Region # 0 - 3]. */
243     stmia r0, {r4-r11}                     /* Write 4 sets of MPU registers [MPU Region # 0 - 3]. */
244
245 #ifdef configTOTAL_MPU_REGIONS
246     #if ( configTOTAL_MPU_REGIONS == 16 )
247         ldmia r2!, {r4-r11}                /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
248         stmia r0, {r4-r11}                 /* Write 4 sets of MPU registers. [MPU Region # 4 - 7]. */
249         ldmia r2!, {r4-r11}                /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
250         stmia r0, {r4-r11}                 /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
251     #endif /* configTOTAL_MPU_REGIONS == 16. */
252 #endif
253
254     ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
255     ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
256     orr r3, #1                             /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
257     str r3, [r0]                           /* Enable MPU. */
258     dsb                                    /* Force memory writes before continuing. */
259
260     /*---------- Restore Context. ---------- */
261     ldr r3, =pxCurrentTCB
262     ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
263     ldr r1, [r2]                           /* r1 = Location of saved context in TCB. */
264
265     ldmdb r1!, {r0, r4-r11}                /* r0 contains PSP after the hardware had saved context. r4-r11 contain hardware saved context. */
266     msr psp, r0
267     stmia r0, {r4-r11}                     /* Copy the hardware saved context on the task stack. */
268     ldmdb r1!, {r3-r11, lr}                /* r3 contains CONTROL register. r4-r11 and LR restored. */
269     msr control, r3
270     str r1, [r2]                           /* Save the location where the context should be saved next as the first member of TCB. */
271
272     mov r0, #0
273     msr basepri, r0
274     bx lr
275
276 /*-----------------------------------------------------------*/
277
278 vPortEnableVFP:
279     /* The FPU enable bits are in the CPACR. */
280     ldr.w r0, =0xE000ED88
281     ldr r1, [r0]
282
283     /* Enable CP10 and CP11 coprocessors, then save back. */
284     orr r1, r1, #( 0xf << 20 )
285     str r1, [r0]
286     bx  r14
287
288 /*-----------------------------------------------------------*/
289
290 xIsPrivileged:
291     mrs r0, control     /* r0 = CONTROL. */
292     tst r0, #1          /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
293     ite ne
294     movne r0, #0        /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
295     moveq r0, #1        /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */
296     bx lr               /* Return. */
297 /*-----------------------------------------------------------*/
298
299 vResetPrivilege:
300     mrs r0, control     /* r0 = CONTROL. */
301     orr r0, r0, #1      /* r0 = r0 | 1. */
302     msr control, r0     /* CONTROL = r0. */
303     bx lr               /* Return to the caller. */
304 /*-----------------------------------------------------------*/
305
306     END