]> begriffs open source - freertos/blob - portable/GCC/ARM_CR5/portASM.S
Use the bigger priority whenever possible. (#760)
[freertos] / portable / GCC / ARM_CR5 / 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
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         VPUSHNE {D0-D15}
80         PUSHNE  {R1}
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         POPNE   {R0}
114         VPOPNE  {D0-D15}
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     LDR R0, vTaskSwitchContextConst
151     BLX R0
152     portRESTORE_CONTEXT
153
154
155 /******************************************************************************
156  * vPortRestoreTaskContext is used to start the scheduler.
157  *****************************************************************************/
158 .type vPortRestoreTaskContext, %function
159 vPortRestoreTaskContext:
160     /* Switch to system mode. */
161     CPS     #SYS_MODE
162     portRESTORE_CONTEXT
163
164 .align 4
165 .type FreeRTOS_IRQ_Handler, %function
166 FreeRTOS_IRQ_Handler:
167
168     /* Return to the interrupted instruction. */
169     SUB     lr, lr, #4
170
171     /* Push the return address and SPSR. */
172     PUSH    {lr}
173     MRS     lr, SPSR
174     PUSH    {lr}
175
176     /* Change to supervisor mode to allow reentry. */
177     CPS     #SVC_MODE
178
179     /* Push used registers. */
180     PUSH    {r0-r4, r12}
181
182     /* Increment nesting count.  r3 holds the address of ulPortInterruptNesting
183     for future use.  r1 holds the original ulPortInterruptNesting value for
184     future use. */
185     LDR     r3, ulPortInterruptNestingConst
186     LDR     r1, [r3]
187     ADD     r4, r1, #1
188     STR     r4, [r3]
189
190     /* Read value from the interrupt acknowledge register, which is stored in r0
191     for future parameter and interrupt clearing use. */
192     LDR     r2, ulICCIARConst
193     LDR     r2, [r2]
194     LDR     r0, [r2]
195
196     /* Ensure bit 2 of the stack pointer is clear.  r2 holds the bit 2 value for
197     future use.  _RB_ Is this ever needed provided the start of the stack is
198     alligned on an 8-byte boundary? */
199     MOV     r2, sp
200     AND     r2, r2, #4
201     SUB     sp, sp, r2
202
203     /* Call the interrupt handler. */
204     PUSH    {r0-r4, lr}
205     LDR     r1, vApplicationIRQHandlerConst
206     BLX     r1
207     POP     {r0-r4, lr}
208     ADD     sp, sp, r2
209
210     CPSID   i
211     DSB
212     ISB
213
214     /* Write the value read from ICCIAR to ICCEOIR. */
215     LDR     r4, ulICCEOIRConst
216     LDR     r4, [r4]
217     STR     r0, [r4]
218
219     /* Restore the old nesting count. */
220     STR     r1, [r3]
221
222     /* A context switch is never performed if the nesting count is not 0. */
223     CMP     r1, #0
224     BNE     exit_without_switch
225
226     /* Did the interrupt request a context switch?  r1 holds the address of
227     ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
228     use. */
229     LDR     r1, =ulPortYieldRequired
230     LDR     r0, [r1]
231     CMP     r0, #0
232     BNE     switch_before_exit
233
234 exit_without_switch:
235     /* No context switch.  Restore used registers, LR_irq and SPSR before
236     returning. */
237     POP     {r0-r4, r12}
238     CPS     #IRQ_MODE
239     POP     {LR}
240     MSR     SPSR_cxsf, LR
241     POP     {LR}
242     MOVS    PC, LR
243
244 switch_before_exit:
245     /* A context swtich is to be performed.  Clear the context switch pending
246     flag. */
247     MOV     r0, #0
248     STR     r0, [r1]
249
250     /* Restore used registers, LR-irq and SPSR before saving the context
251     to the task stack. */
252     POP     {r0-r4, r12}
253     CPS     #IRQ_MODE
254     POP     {LR}
255     MSR     SPSR_cxsf, LR
256     POP     {LR}
257     portSAVE_CONTEXT
258
259     /* Call the function that selects the new task to execute.
260     vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD
261     instructions, or 8 byte aligned stack allocated data.  LR does not need
262     saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */
263     LDR     R0, vTaskSwitchContextConst
264     BLX     R0
265
266     /* Restore the context of, and branch to, the task selected to execute
267     next. */
268     portRESTORE_CONTEXT
269
270 /******************************************************************************
271  * If the application provides an implementation of vApplicationIRQHandler(),
272  * then it will get called directly without saving the FPU registers on
273  * interrupt entry, and this weak implementation of
274  * vApplicationIRQHandler() will not get called.
275  *
276  * If the application provides its own implementation of
277  * vApplicationFPUSafeIRQHandler() then this implementation of
278  * vApplicationIRQHandler() will be called, save the FPU registers, and then
279  * call vApplicationFPUSafeIRQHandler().
280  *
281  * Therefore, if the application writer wants FPU registers to be saved on
282  * interrupt entry their IRQ handler must be called
283  * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
284  * FPU registers to be saved on interrupt entry their IRQ handler must be
285  * called vApplicationIRQHandler().
286  *****************************************************************************/
287 .align 4
288 .weak vApplicationIRQHandler
289 .type vApplicationIRQHandler, %function
290 vApplicationIRQHandler:
291
292     PUSH    {LR}
293
294     #if defined( __ARM_FP )
295         FMRX    R1,  FPSCR
296         VPUSH   {D0-D15}
297         PUSH    {R1}
298
299         LDR     r1, vApplicationFPUSafeIRQHandlerConst
300         BLX     r1
301
302         POP     {R0}
303         VPOP    {D0-D15}
304         VMSR    FPSCR, R0
305     #endif /* __ARM_FP */
306
307     POP {PC}
308
309 ulICCIARConst:  .word ulICCIAR
310 ulICCEOIRConst: .word ulICCEOIR
311 ulICCPMRConst: .word ulICCPMR
312 pxCurrentTCBConst: .word pxCurrentTCB
313 ulCriticalNestingConst: .word ulCriticalNesting
314
315 #if defined( __ARM_FP )
316     ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext
317     vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler
318 #endif /* __ARM_FP */
319
320 ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask
321 vTaskSwitchContextConst: .word vTaskSwitchContext
322 vApplicationIRQHandlerConst: .word vApplicationIRQHandler
323 ulPortInterruptNestingConst: .word ulPortInterruptNesting
324
325 .end