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