]> begriffs open source - freertos/blob - portable/GCC/ARM_CA9/portASM.S
Remove "1 tab == 4 spaces!" line from files that still contain it.
[freertos] / portable / GCC / ARM_CA9 / portASM.S
1 /*\r
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\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
11  *\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
14  *\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
21  *\r
22  * https://www.FreeRTOS.org\r
23  * https://github.com/FreeRTOS\r
24  *\r
25  */\r
26         .eabi_attribute Tag_ABI_align_preserved, 1\r
27         .text\r
28         .arm\r
29 \r
30         .set SYS_MODE,  0x1f\r
31         .set SVC_MODE,  0x13\r
32         .set IRQ_MODE,  0x12\r
33 \r
34         /* Hardware registers. */\r
35         .extern ulICCIAR\r
36         .extern ulICCEOIR\r
37         .extern ulICCPMR\r
38 \r
39         /* Variables and functions. */\r
40         .extern ulMaxAPIPriorityMask\r
41         .extern _freertos_vector_table\r
42         .extern pxCurrentTCB\r
43         .extern vTaskSwitchContext\r
44         .extern vApplicationIRQHandler\r
45         .extern ulPortInterruptNesting\r
46         .extern ulPortTaskHasFPUContext\r
47 \r
48         .global FreeRTOS_IRQ_Handler\r
49         .global FreeRTOS_SWI_Handler\r
50         .global vPortRestoreTaskContext\r
51 \r
52 \r
53 \r
54 \r
55 .macro portSAVE_CONTEXT\r
56 \r
57         /* Save the LR and SPSR onto the system mode stack before switching to\r
58         system mode to save the remaining system mode registers. */\r
59         SRSDB   sp!, #SYS_MODE\r
60         CPS             #SYS_MODE\r
61         PUSH    {R0-R12, R14}\r
62 \r
63         /* Push the critical nesting count. */\r
64         LDR             R2, ulCriticalNestingConst\r
65         LDR             R1, [R2]\r
66         PUSH    {R1}\r
67 \r
68         /* Does the task have a floating point context that needs saving?  If\r
69         ulPortTaskHasFPUContext is 0 then no. */\r
70         LDR             R2, ulPortTaskHasFPUContextConst\r
71         LDR             R3, [R2]\r
72         CMP             R3, #0\r
73 \r
74         /* Save the floating point context, if any. */\r
75         FMRXNE  R1,  FPSCR\r
76         VPUSHNE {D0-D15}\r
77         VPUSHNE {D16-D31}\r
78         PUSHNE  {R1}\r
79 \r
80         /* Save ulPortTaskHasFPUContext itself. */\r
81         PUSH    {R3}\r
82 \r
83         /* Save the stack pointer in the TCB. */\r
84         LDR             R0, pxCurrentTCBConst\r
85         LDR             R1, [R0]\r
86         STR             SP, [R1]\r
87 \r
88         .endm\r
89 \r
90 ; /**********************************************************************/\r
91 \r
92 .macro portRESTORE_CONTEXT\r
93 \r
94         /* Set the SP to point to the stack of the task being restored. */\r
95         LDR             R0, pxCurrentTCBConst\r
96         LDR             R1, [R0]\r
97         LDR             SP, [R1]\r
98 \r
99         /* Is there a floating point context to restore?  If the restored\r
100         ulPortTaskHasFPUContext is zero then no. */\r
101         LDR             R0, ulPortTaskHasFPUContextConst\r
102         POP             {R1}\r
103         STR             R1, [R0]\r
104         CMP             R1, #0\r
105 \r
106         /* Restore the floating point context, if any. */\r
107         POPNE   {R0}\r
108         VPOPNE  {D16-D31}\r
109         VPOPNE  {D0-D15}\r
110         VMSRNE  FPSCR, R0\r
111 \r
112         /* Restore the critical section nesting depth. */\r
113         LDR             R0, ulCriticalNestingConst\r
114         POP             {R1}\r
115         STR             R1, [R0]\r
116 \r
117         /* Ensure the priority mask is correct for the critical nesting depth. */\r
118         LDR             R2, ulICCPMRConst\r
119         LDR             R2, [R2]\r
120         CMP             R1, #0\r
121         MOVEQ   R4, #255\r
122         LDRNE   R4, ulMaxAPIPriorityMaskConst\r
123         LDRNE   R4, [R4]\r
124         STR             R4, [R2]\r
125 \r
126         /* Restore all system mode registers other than the SP (which is already\r
127         being used). */\r
128         POP             {R0-R12, R14}\r
129 \r
130         /* Return to the task code, loading CPSR on the way. */\r
131         RFEIA   sp!\r
132 \r
133         .endm\r
134 \r
135 \r
136 \r
137 \r
138 /******************************************************************************\r
139  * SVC handler is used to start the scheduler.\r
140  *****************************************************************************/\r
141 .align 4\r
142 .type FreeRTOS_SWI_Handler, %function\r
143 FreeRTOS_SWI_Handler:\r
144         /* Save the context of the current task and select a new task to run. */\r
145         portSAVE_CONTEXT\r
146         LDR R0, vTaskSwitchContextConst\r
147         BLX     R0\r
148         portRESTORE_CONTEXT\r
149 \r
150 \r
151 /******************************************************************************\r
152  * vPortRestoreTaskContext is used to start the scheduler.\r
153  *****************************************************************************/\r
154 .type vPortRestoreTaskContext, %function\r
155 vPortRestoreTaskContext:\r
156         /* Switch to system mode. */\r
157         CPS             #SYS_MODE\r
158         portRESTORE_CONTEXT\r
159 \r
160 .align 4\r
161 .type FreeRTOS_IRQ_Handler, %function\r
162 FreeRTOS_IRQ_Handler:\r
163         /* Return to the interrupted instruction. */\r
164         SUB             lr, lr, #4\r
165 \r
166         /* Push the return address and SPSR. */\r
167         PUSH    {lr}\r
168         MRS             lr, SPSR\r
169         PUSH    {lr}\r
170 \r
171         /* Change to supervisor mode to allow reentry. */\r
172         CPS             #SVC_MODE\r
173 \r
174         /* Push used registers. */\r
175         PUSH    {r0-r4, r12}\r
176 \r
177         /* Increment nesting count.  r3 holds the address of ulPortInterruptNesting\r
178         for future use.  r1 holds the original ulPortInterruptNesting value for\r
179         future use. */\r
180         LDR             r3, ulPortInterruptNestingConst\r
181         LDR             r1, [r3]\r
182         ADD             r4, r1, #1\r
183         STR             r4, [r3]\r
184 \r
185         /* Read value from the interrupt acknowledge register, which is stored in r0\r
186         for future parameter and interrupt clearing use. */\r
187         LDR     r2, ulICCIARConst\r
188         LDR             r2, [r2]\r
189         LDR             r0, [r2]\r
190 \r
191         /* Ensure bit 2 of the stack pointer is clear.  r2 holds the bit 2 value for\r
192         future use.  _RB_ Does this ever actually need to be done provided the start\r
193         of the stack is 8-byte aligned? */\r
194         MOV             r2, sp\r
195         AND             r2, r2, #4\r
196         SUB             sp, sp, r2\r
197 \r
198         /* Call the interrupt handler.  r4 pushed to maintain alignment. */\r
199         PUSH    {r0-r4, lr}\r
200         LDR             r1, vApplicationIRQHandlerConst\r
201         BLX             r1\r
202         POP             {r0-r4, lr}\r
203         ADD             sp, sp, r2\r
204 \r
205         CPSID   i\r
206         DSB\r
207         ISB\r
208 \r
209         /* Write the value read from ICCIAR to ICCEOIR. */\r
210         LDR     r4, ulICCEOIRConst\r
211         LDR             r4, [r4]\r
212         STR             r0, [r4]\r
213 \r
214         /* Restore the old nesting count. */\r
215         STR             r1, [r3]\r
216 \r
217         /* A context switch is never performed if the nesting count is not 0. */\r
218         CMP             r1, #0\r
219         BNE             exit_without_switch\r
220 \r
221         /* Did the interrupt request a context switch?  r1 holds the address of\r
222         ulPortYieldRequired and r0 the value of ulPortYieldRequired for future\r
223         use. */\r
224         LDR             r1, =ulPortYieldRequired\r
225         LDR             r0, [r1]\r
226         CMP             r0, #0\r
227         BNE             switch_before_exit\r
228 \r
229 exit_without_switch:\r
230         /* No context switch.  Restore used registers, LR_irq and SPSR before\r
231         returning. */\r
232         POP             {r0-r4, r12}\r
233         CPS             #IRQ_MODE\r
234         POP             {LR}\r
235         MSR             SPSR_cxsf, LR\r
236         POP             {LR}\r
237         MOVS    PC, LR\r
238 \r
239 switch_before_exit:\r
240         /* A context swtich is to be performed.  Clear the context switch pending\r
241         flag. */\r
242         MOV             r0, #0\r
243         STR             r0, [r1]\r
244 \r
245         /* Restore used registers, LR-irq and SPSR before saving the context\r
246         to the task stack. */\r
247         POP             {r0-r4, r12}\r
248         CPS             #IRQ_MODE\r
249         POP             {LR}\r
250         MSR             SPSR_cxsf, LR\r
251         POP             {LR}\r
252         portSAVE_CONTEXT\r
253 \r
254         /* Call the function that selects the new task to execute.\r
255         vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD\r
256         instructions, or 8 byte aligned stack allocated data.  LR does not need\r
257         saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */\r
258         LDR             R0, vTaskSwitchContextConst\r
259         BLX             R0\r
260 \r
261         /* Restore the context of, and branch to, the task selected to execute\r
262         next. */\r
263         portRESTORE_CONTEXT\r
264 \r
265 \r
266 /******************************************************************************\r
267  * If the application provides an implementation of vApplicationIRQHandler(),\r
268  * then it will get called directly without saving the FPU registers on\r
269  * interrupt entry, and this weak implementation of\r
270  * vApplicationIRQHandler() will not get called.\r
271  *\r
272  * If the application provides its own implementation of\r
273  * vApplicationFPUSafeIRQHandler() then this implementation of\r
274  * vApplicationIRQHandler() will be called, save the FPU registers, and then\r
275  * call vApplicationFPUSafeIRQHandler().\r
276  *\r
277  * Therefore, if the application writer wants FPU registers to be saved on\r
278  * interrupt entry their IRQ handler must be called\r
279  * vApplicationFPUSafeIRQHandler(), and if the application writer does not want\r
280  * FPU registers to be saved on interrupt entry their IRQ handler must be\r
281  * called vApplicationIRQHandler().\r
282  *****************************************************************************/\r
283 \r
284 .align 4\r
285 .weak vApplicationIRQHandler\r
286 .type vApplicationIRQHandler, %function\r
287 vApplicationIRQHandler:\r
288         PUSH    {LR}\r
289         FMRX    R1,  FPSCR\r
290         VPUSH   {D0-D15}\r
291         VPUSH   {D16-D31}\r
292         PUSH    {R1}\r
293 \r
294         LDR             r1, vApplicationFPUSafeIRQHandlerConst\r
295         BLX             r1\r
296 \r
297         POP             {R0}\r
298         VPOP    {D16-D31}\r
299         VPOP    {D0-D15}\r
300         VMSR    FPSCR, R0\r
301 \r
302         POP {PC}\r
303 \r
304 \r
305 ulICCIARConst:  .word ulICCIAR\r
306 ulICCEOIRConst: .word ulICCEOIR\r
307 ulICCPMRConst: .word ulICCPMR\r
308 pxCurrentTCBConst: .word pxCurrentTCB\r
309 ulCriticalNestingConst: .word ulCriticalNesting\r
310 ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext\r
311 ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask\r
312 vTaskSwitchContextConst: .word vTaskSwitchContext\r
313 vApplicationIRQHandlerConst: .word vApplicationIRQHandler\r
314 ulPortInterruptNestingConst: .word ulPortInterruptNesting\r
315 vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler\r
316 \r
317 .end\r
318 \r
319 \r
320 \r
321 \r
322 \r