1/*
2 * FreeRTOS Kernel V11.1.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
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 ullICCEOIR
41    .extern ullICCIAR
42    .extern _freertos_vector_table
43
44    .global FreeRTOS_IRQ_Handler
45    .global FreeRTOS_SWI_Handler
46    .global vPortRestoreTaskContext
47
48
49.macro portSAVE_CONTEXT
50
51    /* Switch to use the EL0 stack pointer. */
52    MSR     SPSEL, #0
53
54    /* Save the entire context. */
55    STP     X0, X1, [SP, #-0x10]!
56    STP     X2, X3, [SP, #-0x10]!
57    STP     X4, X5, [SP, #-0x10]!
58    STP     X6, X7, [SP, #-0x10]!
59    STP     X8, X9, [SP, #-0x10]!
60    STP     X10, X11, [SP, #-0x10]!
61    STP     X12, X13, [SP, #-0x10]!
62    STP     X14, X15, [SP, #-0x10]!
63    STP     X16, X17, [SP, #-0x10]!
64    STP     X18, X19, [SP, #-0x10]!
65    STP     X20, X21, [SP, #-0x10]!
66    STP     X22, X23, [SP, #-0x10]!
67    STP     X24, X25, [SP, #-0x10]!
68    STP     X26, X27, [SP, #-0x10]!
69    STP     X28, X29, [SP, #-0x10]!
70    STP     X30, XZR, [SP, #-0x10]!
71
72    /* Save the SPSR. */
73#if defined( GUEST )
74    MRS     X3, SPSR_EL1
75    MRS     X2, ELR_EL1
76#else
77    MRS     X3, SPSR_EL3
78    /* Save the ELR. */
79    MRS     X2, ELR_EL3
80#endif
81
82    STP     X2, X3, [SP, #-0x10]!
83
84    /* Save the critical section nesting depth. */
85    LDR     X0, ullCriticalNestingConst
86    LDR     X3, [X0]
87
88    /* Save the FPU context indicator. */
89    LDR     X0, ullPortTaskHasFPUContextConst
90    LDR     X2, [X0]
91
92    /* Save the FPU context, if any (32 128-bit registers). */
93    CMP     X2, #0
94    B.EQ    1f
95    STP     Q0, Q1, [SP,#-0x20]!
96    STP     Q2, Q3, [SP,#-0x20]!
97    STP     Q4, Q5, [SP,#-0x20]!
98    STP     Q6, Q7, [SP,#-0x20]!
99    STP     Q8, Q9, [SP,#-0x20]!
100    STP     Q10, Q11, [SP,#-0x20]!
101    STP     Q12, Q13, [SP,#-0x20]!
102    STP     Q14, Q15, [SP,#-0x20]!
103    STP     Q16, Q17, [SP,#-0x20]!
104    STP     Q18, Q19, [SP,#-0x20]!
105    STP     Q20, Q21, [SP,#-0x20]!
106    STP     Q22, Q23, [SP,#-0x20]!
107    STP     Q24, Q25, [SP,#-0x20]!
108    STP     Q26, Q27, [SP,#-0x20]!
109    STP     Q28, Q29, [SP,#-0x20]!
110    STP     Q30, Q31, [SP,#-0x20]!
111
1121:
113    /* Store the critical nesting count and FPU context indicator. */
114    STP     X2, X3, [SP, #-0x10]!
115
116    LDR     X0, pxCurrentTCBConst
117    LDR     X1, [X0]
118    MOV     X0, SP   /* Move SP into X0 for saving. */
119    STR     X0, [X1]
120
121    /* Switch to use the ELx stack pointer. */
122    MSR     SPSEL, #1
123
124    .endm
125
126; /**********************************************************************/
127
128.macro portRESTORE_CONTEXT
129
130    /* Switch to use the EL0 stack pointer. */
131    MSR     SPSEL, #0
132
133    /* Set the SP to point to the stack of the task being restored. */
134    LDR     X0, pxCurrentTCBConst
135    LDR     X1, [X0]
136    LDR     X0, [X1]
137    MOV     SP, X0
138
139    LDP     X2, X3, [SP], #0x10  /* Critical nesting and FPU context. */
140
141    /* Set the PMR register to be correct for the current critical nesting
142    depth. */
143    LDR     X0, ullCriticalNestingConst /* X0 holds the address of ullCriticalNesting. */
144    MOV     X1, #255                    /* X1 holds the unmask value. */
145    LDR     X4, ullICCPMRConst          /* X4 holds the address of the ICCPMR constant. */
146    CMP     X3, #0
147    LDR     X5, [X4]                    /* X5 holds the address of the ICCPMR register. */
148    B.EQ    1f
149    LDR     X6, ullMaxAPIPriorityMaskConst
150    LDR     X1, [X6]                    /* X1 holds the mask value. */
1511:
152    STR     W1, [X5]                    /* Write the mask value to ICCPMR. */
153    DSB     SY                          /* _RB_Barriers probably not required here. */
154    ISB     SY
155    STR     X3, [X0]                    /* Restore the task's critical nesting count. */
156
157    /* Restore the FPU context indicator. */
158    LDR     X0, ullPortTaskHasFPUContextConst
159    STR     X2, [X0]
160
161    /* Restore the FPU context, if any. */
162    CMP     X2, #0
163    B.EQ    1f
164    LDP     Q30, Q31, [SP], #0x20
165    LDP     Q28, Q29, [SP], #0x20
166    LDP     Q26, Q27, [SP], #0x20
167    LDP     Q24, Q25, [SP], #0x20
168    LDP     Q22, Q23, [SP], #0x20
169    LDP     Q20, Q21, [SP], #0x20
170    LDP     Q18, Q19, [SP], #0x20
171    LDP     Q16, Q17, [SP], #0x20
172    LDP     Q14, Q15, [SP], #0x20
173    LDP     Q12, Q13, [SP], #0x20
174    LDP     Q10, Q11, [SP], #0x20
175    LDP     Q8, Q9, [SP], #0x20
176    LDP     Q6, Q7, [SP], #0x20
177    LDP     Q4, Q5, [SP], #0x20
178    LDP     Q2, Q3, [SP], #0x20
179    LDP     Q0, Q1, [SP], #0x20
1801:
181    LDP     X2, X3, [SP], #0x10  /* SPSR and ELR. */
182
183#if defined( GUEST )
184    /* Restore the SPSR. */
185    MSR     SPSR_EL1, X3
186    /* Restore the ELR. */
187    MSR     ELR_EL1, X2
188#else
189    /* Restore the SPSR. */
190    MSR     SPSR_EL3, X3 /*_RB_ Assumes started in EL3. */
191    /* Restore the ELR. */
192    MSR     ELR_EL3, X2
193#endif
194
195    LDP     X30, XZR, [SP], #0x10
196    LDP     X28, X29, [SP], #0x10
197    LDP     X26, X27, [SP], #0x10
198    LDP     X24, X25, [SP], #0x10
199    LDP     X22, X23, [SP], #0x10
200    LDP     X20, X21, [SP], #0x10
201    LDP     X18, X19, [SP], #0x10
202    LDP     X16, X17, [SP], #0x10
203    LDP     X14, X15, [SP], #0x10
204    LDP     X12, X13, [SP], #0x10
205    LDP     X10, X11, [SP], #0x10
206    LDP     X8, X9, [SP], #0x10
207    LDP     X6, X7, [SP], #0x10
208    LDP     X4, X5, [SP], #0x10
209    LDP     X2, X3, [SP], #0x10
210    LDP     X0, X1, [SP], #0x10
211
212    /* Switch to use the ELx stack pointer.  _RB_ Might not be required. */
213    MSR     SPSEL, #1
214
215    ERET
216
217    .endm
218
219
220/******************************************************************************
221 * FreeRTOS_SWI_Handler handler is used to perform a context switch.
222 *****************************************************************************/
223.align 8
224.type FreeRTOS_SWI_Handler, %function
225FreeRTOS_SWI_Handler:
226    /* Save the context of the current task and select a new task to run. */
227    portSAVE_CONTEXT
228#if defined( GUEST )
229    MRS     X0, ESR_EL1
230#else
231    MRS     X0, ESR_EL3
232#endif
233
234    LSR     X1, X0, #26
235
236#if defined( GUEST )
237    CMP     X1, #0x15   /* 0x15 = SVC instruction. */
238#else
239    CMP     X1, #0x17   /* 0x17 = SMC instruction. */
240#endif
241    B.NE    FreeRTOS_Abort
242    BL      vTaskSwitchContext
243
244    portRESTORE_CONTEXT
245
246FreeRTOS_Abort:
247    /* Full ESR is in X0, exception class code is in X1. */
248    B       .
249
250/******************************************************************************
251 * vPortRestoreTaskContext is used to start the scheduler.
252 *****************************************************************************/
253.align 8
254.type vPortRestoreTaskContext, %function
255vPortRestoreTaskContext:
256.set freertos_vector_base,  _freertos_vector_table
257
258    /* Install the FreeRTOS interrupt handlers. */
259    LDR     X1, =freertos_vector_base
260#if defined( GUEST )
261    MSR     VBAR_EL1, X1
262#else
263    MSR     VBAR_EL3, X1
264#endif
265    DSB     SY
266    ISB     SY
267
268    /* Start the first task. */
269    portRESTORE_CONTEXT
270
271
272/******************************************************************************
273 * FreeRTOS_IRQ_Handler handles IRQ entry and exit.
274 *****************************************************************************/
275.align 8
276.type FreeRTOS_IRQ_Handler, %function
277FreeRTOS_IRQ_Handler:
278    /* Save volatile registers. */
279    STP     X0, X1, [SP, #-0x10]!
280    STP     X2, X3, [SP, #-0x10]!
281    STP     X4, X5, [SP, #-0x10]!
282    STP     X6, X7, [SP, #-0x10]!
283    STP     X8, X9, [SP, #-0x10]!
284    STP     X10, X11, [SP, #-0x10]!
285    STP     X12, X13, [SP, #-0x10]!
286    STP     X14, X15, [SP, #-0x10]!
287    STP     X16, X17, [SP, #-0x10]!
288    STP     X18, X19, [SP, #-0x10]!
289    STP     X29, X30, [SP, #-0x10]!
290
291    /* Save the SPSR and ELR. */
292#if defined( GUEST )
293    MRS     X3, SPSR_EL1
294    MRS     X2, ELR_EL1
295#else
296    MRS     X3, SPSR_EL3
297    MRS     X2, ELR_EL3
298#endif
299    STP     X2, X3, [SP, #-0x10]!
300
301    /* Increment the interrupt nesting counter. */
302    LDR     X5, ullPortInterruptNestingConst
303    LDR     X1, [X5]    /* Old nesting count in X1. */
304    ADD     X6, X1, #1
305    STR     X6, [X5]    /* Address of nesting count variable in X5. */
306
307    /* Maintain the interrupt nesting information across the function call. */
308    STP     X1, X5, [SP, #-0x10]!
309
310    /* Read value from the interrupt acknowledge register, which is stored in W0
311    for future parameter and interrupt clearing use. */
312    LDR     X2, ullICCIARConst
313    LDR     X3, [X2]
314    LDR     W0, [X3]    /* ICCIAR in W0 as parameter. */
315
316    /* Maintain the ICCIAR value across the function call. */
317    STP     X0, X1, [SP, #-0x10]!
318
319    /* Call the C handler. */
320    BL vApplicationIRQHandler
321
322    /* Disable interrupts. */
323    MSR     DAIFSET, #2
324    DSB     SY
325    ISB     SY
326
327    /* Restore the ICCIAR value. */
328    LDP     X0, X1, [SP], #0x10
329
330    /* End IRQ processing by writing ICCIAR to the EOI register. */
331    LDR     X4, ullICCEOIRConst
332    LDR     X4, [X4]
333    STR     W0, [X4]
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
417ullICCPMRConst: .dword ullICCPMR
418ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask
419ullPortInterruptNestingConst: .dword ullPortInterruptNesting
420ullPortYieldRequiredConst: .dword ullPortYieldRequired
421ullICCIARConst: .dword ullICCIAR
422ullICCEOIRConst: .dword ullICCEOIR
423vApplicationIRQHandlerConst: .word vApplicationIRQHandler
424
425
426
427.end
428