xref: /Kernel-v10.6.2/portable/GCC/ARM_CA53_64_BIT_SRE/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
31    /* Variables and functions. */
32    .extern ullMaxAPIPriorityMask
33    .extern pxCurrentTCB
34    .extern vTaskSwitchContext
35    .extern vApplicationIRQHandler
36    .extern ullPortInterruptNesting
37    .extern ullPortTaskHasFPUContext
38    .extern ullCriticalNesting
39    .extern ullPortYieldRequired
40    .extern _freertos_vector_table
41
42    .global FreeRTOS_IRQ_Handler
43    .global FreeRTOS_SWI_Handler
44    .global vPortRestoreTaskContext
45
46
47.macro portSAVE_CONTEXT
48
49    /* Switch to use the EL0 stack pointer. */
50    MSR     SPSEL, #0
51
52    /* Save the entire context. */
53    STP     X0, X1, [SP, #-0x10]!
54    STP     X2, X3, [SP, #-0x10]!
55    STP     X4, X5, [SP, #-0x10]!
56    STP     X6, X7, [SP, #-0x10]!
57    STP     X8, X9, [SP, #-0x10]!
58    STP     X10, X11, [SP, #-0x10]!
59    STP     X12, X13, [SP, #-0x10]!
60    STP     X14, X15, [SP, #-0x10]!
61    STP     X16, X17, [SP, #-0x10]!
62    STP     X18, X19, [SP, #-0x10]!
63    STP     X20, X21, [SP, #-0x10]!
64    STP     X22, X23, [SP, #-0x10]!
65    STP     X24, X25, [SP, #-0x10]!
66    STP     X26, X27, [SP, #-0x10]!
67    STP     X28, X29, [SP, #-0x10]!
68    STP     X30, XZR, [SP, #-0x10]!
69
70    /* Save the SPSR. */
71#if defined( GUEST )
72    MRS     X3, SPSR_EL1
73    MRS     X2, ELR_EL1
74#else
75    MRS     X3, SPSR_EL3
76    /* Save the ELR. */
77    MRS     X2, ELR_EL3
78#endif
79
80    STP     X2, X3, [SP, #-0x10]!
81
82    /* Save the critical section nesting depth. */
83    LDR     X0, ullCriticalNestingConst
84    LDR     X3, [X0]
85
86    /* Save the FPU context indicator. */
87    LDR     X0, ullPortTaskHasFPUContextConst
88    LDR     X2, [X0]
89
90    /* Save the FPU context, if any (32 128-bit registers). */
91    CMP     X2, #0
92    B.EQ    1f
93    STP     Q0, Q1, [SP,#-0x20]!
94    STP     Q2, Q3, [SP,#-0x20]!
95    STP     Q4, Q5, [SP,#-0x20]!
96    STP     Q6, Q7, [SP,#-0x20]!
97    STP     Q8, Q9, [SP,#-0x20]!
98    STP     Q10, Q11, [SP,#-0x20]!
99    STP     Q12, Q13, [SP,#-0x20]!
100    STP     Q14, Q15, [SP,#-0x20]!
101    STP     Q16, Q17, [SP,#-0x20]!
102    STP     Q18, Q19, [SP,#-0x20]!
103    STP     Q20, Q21, [SP,#-0x20]!
104    STP     Q22, Q23, [SP,#-0x20]!
105    STP     Q24, Q25, [SP,#-0x20]!
106    STP     Q26, Q27, [SP,#-0x20]!
107    STP     Q28, Q29, [SP,#-0x20]!
108    STP     Q30, Q31, [SP,#-0x20]!
109
1101:
111    /* Store the critical nesting count and FPU context indicator. */
112    STP     X2, X3, [SP, #-0x10]!
113
114    LDR     X0, pxCurrentTCBConst
115    LDR     X1, [X0]
116    MOV     X0, SP   /* Move SP into X0 for saving. */
117    STR     X0, [X1]
118
119    /* Switch to use the ELx stack pointer. */
120    MSR     SPSEL, #1
121
122    .endm
123
124; /**********************************************************************/
125
126.macro portRESTORE_CONTEXT
127
128    /* Switch to use the EL0 stack pointer. */
129    MSR     SPSEL, #0
130
131    /* Set the SP to point to the stack of the task being restored. */
132    LDR     X0, pxCurrentTCBConst
133    LDR     X1, [X0]
134    LDR     X0, [X1]
135    MOV     SP, X0
136
137    LDP     X2, X3, [SP], #0x10  /* Critical nesting and FPU context. */
138
139    /* Set the PMR register to be correct for the current critical nesting
140    depth. */
141    LDR     X0, ullCriticalNestingConst /* X0 holds the address of ullCriticalNesting. */
142    MOV     X1, #255                    /* X1 holds the unmask value. */
143    CMP     X3, #0
144    B.EQ    1f
145    LDR     X6, ullMaxAPIPriorityMaskConst
146    LDR     X1, [X6]                    /* X1 holds the mask value. */
1471:
148    MSR     s3_0_c4_c6_0, X1            /* Write the mask value to ICCPMR. s3_0_c4_c6_0 is ICC_PMR_EL1. */
149    DSB     SY                          /* _RB_Barriers probably not required here. */
150    ISB     SY
151    STR     X3, [X0]                    /* Restore the task's critical nesting count. */
152
153    /* Restore the FPU context indicator. */
154    LDR     X0, ullPortTaskHasFPUContextConst
155    STR     X2, [X0]
156
157    /* Restore the FPU context, if any. */
158    CMP     X2, #0
159    B.EQ    1f
160    LDP     Q30, Q31, [SP], #0x20
161    LDP     Q28, Q29, [SP], #0x20
162    LDP     Q26, Q27, [SP], #0x20
163    LDP     Q24, Q25, [SP], #0x20
164    LDP     Q22, Q23, [SP], #0x20
165    LDP     Q20, Q21, [SP], #0x20
166    LDP     Q18, Q19, [SP], #0x20
167    LDP     Q16, Q17, [SP], #0x20
168    LDP     Q14, Q15, [SP], #0x20
169    LDP     Q12, Q13, [SP], #0x20
170    LDP     Q10, Q11, [SP], #0x20
171    LDP     Q8, Q9, [SP], #0x20
172    LDP     Q6, Q7, [SP], #0x20
173    LDP     Q4, Q5, [SP], #0x20
174    LDP     Q2, Q3, [SP], #0x20
175    LDP     Q0, Q1, [SP], #0x20
1761:
177    LDP     X2, X3, [SP], #0x10  /* SPSR and ELR. */
178
179#if defined( GUEST )
180    /* Restore the SPSR. */
181    MSR     SPSR_EL1, X3
182    /* Restore the ELR. */
183    MSR     ELR_EL1, X2
184#else
185    /* Restore the SPSR. */
186    MSR     SPSR_EL3, X3 /*_RB_ Assumes started in EL3. */
187    /* Restore the ELR. */
188    MSR     ELR_EL3, X2
189#endif
190
191    LDP     X30, XZR, [SP], #0x10
192    LDP     X28, X29, [SP], #0x10
193    LDP     X26, X27, [SP], #0x10
194    LDP     X24, X25, [SP], #0x10
195    LDP     X22, X23, [SP], #0x10
196    LDP     X20, X21, [SP], #0x10
197    LDP     X18, X19, [SP], #0x10
198    LDP     X16, X17, [SP], #0x10
199    LDP     X14, X15, [SP], #0x10
200    LDP     X12, X13, [SP], #0x10
201    LDP     X10, X11, [SP], #0x10
202    LDP     X8, X9, [SP], #0x10
203    LDP     X6, X7, [SP], #0x10
204    LDP     X4, X5, [SP], #0x10
205    LDP     X2, X3, [SP], #0x10
206    LDP     X0, X1, [SP], #0x10
207
208    /* Switch to use the ELx stack pointer.  _RB_ Might not be required. */
209    MSR     SPSEL, #1
210
211    ERET
212
213    .endm
214
215
216/******************************************************************************
217 * FreeRTOS_SWI_Handler handler is used to perform a context switch.
218 *****************************************************************************/
219.align 8
220.type FreeRTOS_SWI_Handler, %function
221FreeRTOS_SWI_Handler:
222    /* Save the context of the current task and select a new task to run. */
223    portSAVE_CONTEXT
224#if defined( GUEST )
225    MRS     X0, ESR_EL1
226#else
227    MRS     X0, ESR_EL3
228#endif
229
230    LSR     X1, X0, #26
231
232#if defined( GUEST )
233    CMP     X1, #0x15   /* 0x15 = SVC instruction. */
234#else
235    CMP     X1, #0x17   /* 0x17 = SMC instruction. */
236#endif
237    B.NE    FreeRTOS_Abort
238    BL      vTaskSwitchContext
239
240    portRESTORE_CONTEXT
241
242FreeRTOS_Abort:
243    /* Full ESR is in X0, exception class code is in X1. */
244    B       .
245
246/******************************************************************************
247 * vPortRestoreTaskContext is used to start the scheduler.
248 *****************************************************************************/
249.align 8
250.type vPortRestoreTaskContext, %function
251vPortRestoreTaskContext:
252.set freertos_vector_base,  _freertos_vector_table
253
254    /* Install the FreeRTOS interrupt handlers. */
255    LDR     X1, =freertos_vector_base
256#if defined( GUEST )
257    MSR     VBAR_EL1, X1
258#else
259    MSR     VBAR_EL3, X1
260#endif
261    DSB     SY
262    ISB     SY
263
264    /* Start the first task. */
265    portRESTORE_CONTEXT
266
267
268/******************************************************************************
269 * FreeRTOS_IRQ_Handler handles IRQ entry and exit.
270
271 * This handler is supposed to be used only for IRQs and never for FIQs. Per ARM
272 * GIC documentation [1], Group 0 interrupts are always signaled as FIQs. Since
273 * this handler is only for IRQs, We can safely assume Group 1 while accessing
274 * Interrupt Acknowledge and End Of Interrupt registers and therefore, use
275 * ICC_IAR1_EL1 and ICC_EOIR1_EL1.
276 *
277 * [1] https://developer.arm.com/documentation/198123/0300/Arm-CoreLink-GIC-fundamentals
278 *****************************************************************************/
279.align 8
280.type FreeRTOS_IRQ_Handler, %function
281FreeRTOS_IRQ_Handler:
282    /* Save volatile registers. */
283    STP     X0, X1, [SP, #-0x10]!
284    STP     X2, X3, [SP, #-0x10]!
285    STP     X4, X5, [SP, #-0x10]!
286    STP     X6, X7, [SP, #-0x10]!
287    STP     X8, X9, [SP, #-0x10]!
288    STP     X10, X11, [SP, #-0x10]!
289    STP     X12, X13, [SP, #-0x10]!
290    STP     X14, X15, [SP, #-0x10]!
291    STP     X16, X17, [SP, #-0x10]!
292    STP     X18, X19, [SP, #-0x10]!
293    STP     X29, X30, [SP, #-0x10]!
294
295    /* Save the SPSR and ELR. */
296#if defined( GUEST )
297    MRS     X3, SPSR_EL1
298    MRS     X2, ELR_EL1
299#else
300    MRS     X3, SPSR_EL3
301    MRS     X2, ELR_EL3
302#endif
303    STP     X2, X3, [SP, #-0x10]!
304
305    /* Increment the interrupt nesting counter. */
306    LDR     X5, ullPortInterruptNestingConst
307    LDR     X1, [X5]    /* Old nesting count in X1. */
308    ADD     X6, X1, #1
309    STR     X6, [X5]    /* Address of nesting count variable in X5. */
310
311    /* Maintain the interrupt nesting information across the function call. */
312    STP     X1, X5, [SP, #-0x10]!
313
314    /* Read interrupt ID from the interrupt acknowledge register and store it
315    in X0 for future parameter and interrupt clearing use. */
316    MRS     X0, S3_0_C12_C12_0  /* S3_0_C12_C12_0 is ICC_IAR1_EL1. */
317
318    /* Maintain the interrupt ID value across the function call. */
319    STP     X0, X1, [SP, #-0x10]!
320
321    /* Call the C handler. */
322    BL vApplicationIRQHandler
323
324    /* Disable interrupts. */
325    MSR     DAIFSET, #2
326    DSB     SY
327    ISB     SY
328
329    /* Restore the interrupt ID value. */
330    LDP     X0, X1, [SP], #0x10
331
332    /* End IRQ processing by writing interrupt ID value to the EOI register. */
333    MSR     S3_0_C12_C12_1, X0  /* S3_0_C12_C12_1 is ICC_EOIR1_EL1. */
334
335    /* Restore the critical nesting count. */
336    LDP     X1, X5, [SP], #0x10
337    STR     X1, [X5]
338
339    /* Has interrupt nesting unwound? */
340    CMP     X1, #0
341    B.NE    Exit_IRQ_No_Context_Switch
342
343    /* Is a context switch required? */
344    LDR     X0, ullPortYieldRequiredConst
345    LDR     X1, [X0]
346    CMP     X1, #0
347    B.EQ    Exit_IRQ_No_Context_Switch
348
349    /* Reset ullPortYieldRequired to 0. */
350    MOV     X2, #0
351    STR     X2, [X0]
352
353    /* Restore volatile registers. */
354    LDP     X4, X5, [SP], #0x10  /* SPSR and ELR. */
355#if defined( GUEST )
356    MSR     SPSR_EL1, X5
357    MSR     ELR_EL1, X4
358#else
359    MSR     SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */
360    MSR     ELR_EL3, X4
361#endif
362    DSB     SY
363    ISB     SY
364
365    LDP     X29, X30, [SP], #0x10
366    LDP     X18, X19, [SP], #0x10
367    LDP     X16, X17, [SP], #0x10
368    LDP     X14, X15, [SP], #0x10
369    LDP     X12, X13, [SP], #0x10
370    LDP     X10, X11, [SP], #0x10
371    LDP     X8, X9, [SP], #0x10
372    LDP     X6, X7, [SP], #0x10
373    LDP     X4, X5, [SP], #0x10
374    LDP     X2, X3, [SP], #0x10
375    LDP     X0, X1, [SP], #0x10
376
377    /* Save the context of the current task and select a new task to run. */
378    portSAVE_CONTEXT
379    BL vTaskSwitchContext
380    portRESTORE_CONTEXT
381
382Exit_IRQ_No_Context_Switch:
383    /* Restore volatile registers. */
384    LDP     X4, X5, [SP], #0x10  /* SPSR and ELR. */
385#if defined( GUEST )
386    MSR     SPSR_EL1, X5
387    MSR     ELR_EL1, X4
388#else
389    MSR     SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */
390    MSR     ELR_EL3, X4
391#endif
392    DSB     SY
393    ISB     SY
394
395    LDP     X29, X30, [SP], #0x10
396    LDP     X18, X19, [SP], #0x10
397    LDP     X16, X17, [SP], #0x10
398    LDP     X14, X15, [SP], #0x10
399    LDP     X12, X13, [SP], #0x10
400    LDP     X10, X11, [SP], #0x10
401    LDP     X8, X9, [SP], #0x10
402    LDP     X6, X7, [SP], #0x10
403    LDP     X4, X5, [SP], #0x10
404    LDP     X2, X3, [SP], #0x10
405    LDP     X0, X1, [SP], #0x10
406
407    ERET
408
409
410
411
412.align 8
413pxCurrentTCBConst: .dword pxCurrentTCB
414ullCriticalNestingConst: .dword ullCriticalNesting
415ullPortTaskHasFPUContextConst: .dword ullPortTaskHasFPUContext
416
417ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask
418ullPortInterruptNestingConst: .dword ullPortInterruptNesting
419ullPortYieldRequiredConst: .dword ullPortYieldRequired
420
421.end
422