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