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