xref: /Kernel-v10.6.2/portable/GCC/ARM_CRx_No_GIC/portASM.S (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1/*
2 * FreeRTOS Kernel V10.6.2
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    /* Variables and functions. */
37    .extern ulMaxAPIPriorityMask
38    .extern _freertos_vector_table
39    .extern pxCurrentTCB
40    .extern vTaskSwitchContext
41    .extern vApplicationIRQHandler
42    .extern ulPortInterruptNesting
43    .extern ulPortTaskHasFPUContext
44    .extern ulICCEOIR
45    .extern ulPortYieldRequired
46
47    .global FreeRTOS_IRQ_Handler
48    .global FreeRTOS_SVC_Handler
49    .global vPortRestoreTaskContext
50
51
52.macro portSAVE_CONTEXT
53
54    /* Save the LR and SPSR onto the system mode stack before switching to
55    system mode to save the remaining system mode registers. */
56    SRSDB   sp!, #SYS_MODE
57    CPS     #SYS_MODE
58    PUSH    {R0-R12, R14}
59
60    /* Push the critical nesting count. */
61    LDR     R2, ulCriticalNestingConst
62    LDR     R1, [R2]
63    PUSH    {R1}
64
65    /* Does the task have a floating point context that needs saving?  If
66    ulPortTaskHasFPUContext is 0 then no. */
67    LDR     R2, ulPortTaskHasFPUContextConst
68    LDR     R3, [R2]
69    CMP     R3, #0
70
71    /* Save the floating point context, if any. */
72    FMRXNE  R1,  FPSCR
73    VPUSHNE {D0-D15}
74#if configFPU_D32 == 1
75    VPUSHNE {D16-D31}
76#endif /* configFPU_D32 */
77    PUSHNE  {R1}
78
79    /* Save ulPortTaskHasFPUContext itself. */
80    PUSH    {R3}
81
82    /* Save the stack pointer in the TCB. */
83    LDR     R0, pxCurrentTCBConst
84    LDR     R1, [R0]
85    STR     SP, [R1]
86
87    .endm
88
89; /**********************************************************************/
90
91.macro portRESTORE_CONTEXT
92
93    /* Set the SP to point to the stack of the task being restored. */
94    LDR     R0, pxCurrentTCBConst
95    LDR     R1, [R0]
96    LDR     SP, [R1]
97
98    /* Is there a floating point context to restore?  If the restored
99    ulPortTaskHasFPUContext is zero then no. */
100    LDR     R0, ulPortTaskHasFPUContextConst
101    POP     {R1}
102    STR     R1, [R0]
103    CMP     R1, #0
104
105    /* Restore the floating point context, if any. */
106    POPNE   {R0}
107#if configFPU_D32 == 1
108    VPOPNE  {D16-D31}
109#endif /* configFPU_D32 */
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    /* Restore all system mode registers other than the SP (which is already
119    being used). */
120    POP     {R0-R12, R14}
121
122    /* Return to the task code, loading CPSR on the way. */
123    RFEIA   sp!
124
125    .endm
126
127
128
129
130/******************************************************************************
131 * SVC handler is used to yield.
132 *****************************************************************************/
133.align 4
134.type FreeRTOS_SVC_Handler, %function
135FreeRTOS_SVC_Handler:
136    /* Save the context of the current task and select a new task to run. */
137    portSAVE_CONTEXT
138    LDR R0, vTaskSwitchContextConst
139    BLX R0
140    portRESTORE_CONTEXT
141
142
143/******************************************************************************
144 * vPortRestoreTaskContext is used to start the scheduler.
145 *****************************************************************************/
146.align 4
147.type vPortRestoreTaskContext, %function
148vPortRestoreTaskContext:
149    /* Switch to system mode. */
150    CPS     #SYS_MODE
151    portRESTORE_CONTEXT
152
153.align 4
154.type FreeRTOS_IRQ_Handler, %function
155FreeRTOS_IRQ_Handler:
156    /* Return to the interrupted instruction. */
157    SUB     lr, lr, #4
158
159    /* Push the return address and SPSR. */
160    PUSH    {lr}
161    MRS     lr, SPSR
162    PUSH    {lr}
163
164    /* Change to supervisor mode to allow reentry. */
165    CPS     #0x13
166
167    /* Push used registers. */
168    PUSH    {r0-r3, r12}
169
170    /* Increment nesting count.  r3 holds the address of ulPortInterruptNesting
171    for future use.  r1 holds the original ulPortInterruptNesting value for
172    future use. */
173    LDR     r3, ulPortInterruptNestingConst
174    LDR     r1, [r3]
175    ADD     r0, r1, #1
176    STR     r0, [r3]
177
178    /* Ensure bit 2 of the stack pointer is clear.  r2 holds the bit 2 value for
179    future use. */
180    MOV     r0, sp
181    AND     r2, r0, #4
182    SUB     sp, sp, r2
183
184    /* Call the interrupt handler. */
185    PUSH    {r0-r3, lr}
186    LDR     r1, vApplicationIRQHandlerConst
187    BLX     r1
188    POP     {r0-r3, lr}
189    ADD     sp, sp, r2
190
191    CPSID   i
192    DSB
193    ISB
194
195    /* Write to the EOI register. */
196    LDR     r0, ulICCEOIRConst
197    LDR     r2, [r0]
198    STR     r0, [r2]
199
200    /* Restore the old nesting count. */
201    STR     r1, [r3]
202
203    /* A context switch is never performed if the nesting count is not 0. */
204    CMP     r1, #0
205    BNE     exit_without_switch
206
207    /* Did the interrupt request a context switch?  r1 holds the address of
208    ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
209    use. */
210    LDR     r1, ulPortYieldRequiredConst
211    LDR     r0, [r1]
212    CMP     r0, #0
213    BNE     switch_before_exit
214
215exit_without_switch:
216    /* No context switch.  Restore used registers, LR_irq and SPSR before
217    returning. */
218    POP     {r0-r3, r12}
219    CPS     #IRQ_MODE
220    POP     {LR}
221    MSR     SPSR_cxsf, LR
222    POP     {LR}
223    MOVS    PC, LR
224
225switch_before_exit:
226    /* A context swtich is to be performed.  Clear the context switch pending
227    flag. */
228    MOV     r0, #0
229    STR     r0, [r1]
230
231    /* Restore used registers, LR-irq and SPSR before saving the context
232    to the task stack. */
233    POP     {r0-r3, r12}
234    CPS     #IRQ_MODE
235    POP     {LR}
236    MSR     SPSR_cxsf, LR
237    POP     {LR}
238    portSAVE_CONTEXT
239
240    /* Call the function that selects the new task to execute.
241    vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD
242    instructions, or 8 byte aligned stack allocated data.  LR does not need
243    saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */
244    LDR     R0, vTaskSwitchContextConst
245    BLX     R0
246
247    /* Restore the context of, and branch to, the task selected to execute
248    next. */
249    portRESTORE_CONTEXT
250
251ulICCEOIRConst: .word ulICCEOIR
252pxCurrentTCBConst: .word pxCurrentTCB
253ulCriticalNestingConst: .word ulCriticalNesting
254ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext
255vTaskSwitchContextConst: .word vTaskSwitchContext
256vApplicationIRQHandlerConst: .word vApplicationIRQHandler
257ulPortInterruptNestingConst: .word ulPortInterruptNesting
258ulPortYieldRequiredConst: .word ulPortYieldRequired
259
260.end
261