2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
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:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
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.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
28 .eabi_attribute Tag_ABI_align_preserved, 1
36 /* Hardware registers. */
41 /* Variables and functions. */
42 .extern ulMaxAPIPriorityMask
43 .extern _freertos_vector_table
45 .extern vTaskSwitchContext
46 .extern vApplicationIRQHandler
47 .extern ulPortInterruptNesting
48 .extern ulPortTaskHasFPUContext
50 .global FreeRTOS_IRQ_Handler
51 .global FreeRTOS_SWI_Handler
52 .global vPortRestoreTaskContext
57 .macro portSAVE_CONTEXT
59 /* Save the LR and SPSR onto the system mode stack before switching to
60 system mode to save the remaining system mode registers. */
65 /* Push the critical nesting count. */
66 LDR R2, ulCriticalNestingConst
70 /* Does the task have a floating point context that needs saving? If
71 ulPortTaskHasFPUContext is 0 then no. */
72 LDR R2, ulPortTaskHasFPUContextConst
76 /* Save the floating point context, if any. */
82 /* Save ulPortTaskHasFPUContext itself. */
85 /* Save the stack pointer in the TCB. */
86 LDR R0, pxCurrentTCBConst
92 ; /**********************************************************************/
94 .macro portRESTORE_CONTEXT
96 /* Set the SP to point to the stack of the task being restored. */
97 LDR R0, pxCurrentTCBConst
101 /* Is there a floating point context to restore? If the restored
102 ulPortTaskHasFPUContext is zero then no. */
103 LDR R0, ulPortTaskHasFPUContextConst
108 /* Restore the floating point context, if any. */
114 /* Restore the critical section nesting depth. */
115 LDR R0, ulCriticalNestingConst
119 /* Ensure the priority mask is correct for the critical nesting depth. */
120 LDR R2, ulICCPMRConst
124 LDRNE R4, ulMaxAPIPriorityMaskConst
128 /* Restore all system mode registers other than the SP (which is already
132 /* Return to the task code, loading CPSR on the way. */
140 /******************************************************************************
141 * SVC handler is used to start the scheduler.
142 *****************************************************************************/
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. */
149 /* Ensure bit 2 of the stack pointer is clear. */
154 LDR R0, vTaskSwitchContextConst
160 /******************************************************************************
161 * vPortRestoreTaskContext is used to start the scheduler.
162 *****************************************************************************/
163 .type vPortRestoreTaskContext, %function
164 vPortRestoreTaskContext:
165 /* Switch to system mode. */
170 .type FreeRTOS_IRQ_Handler, %function
171 FreeRTOS_IRQ_Handler:
172 /* Return to the interrupted instruction. */
175 /* Push the return address and SPSR. */
180 /* Change to supervisor mode to allow reentry. */
183 /* Push used registers. */
186 /* Increment nesting count. r3 holds the address of ulPortInterruptNesting
187 for future use. r1 holds the original ulPortInterruptNesting value for
189 LDR r3, ulPortInterruptNestingConst
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
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? */
207 /* Call the interrupt handler. r4 pushed to maintain alignment. */
209 LDR r1, vApplicationIRQHandlerConst
218 /* Write the value read from ICCIAR to ICCEOIR. */
219 LDR r4, ulICCEOIRConst
223 /* Restore the old nesting count. */
226 /* A context switch is never performed if the nesting count is not 0. */
228 BNE exit_without_switch
230 /* Did the interrupt request a context switch? r1 holds the address of
231 ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
233 LDR r1, =ulPortYieldRequired
236 BNE switch_before_exit
239 /* No context switch. Restore used registers, LR_irq and SPSR before
249 /* A context swtich is to be performed. Clear the context switch pending
254 /* Restore used registers, LR-irq and SPSR before saving the context
255 to the task stack. */
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
273 LDR R0, vTaskSwitchContextConst
276 /* Restore the context of, and branch to, the task selected to execute
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.
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().
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 *****************************************************************************/
300 .weak vApplicationIRQHandler
301 .type vApplicationIRQHandler, %function
302 vApplicationIRQHandler:
309 LDR r1, vApplicationFPUSafeIRQHandlerConst
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