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
38 /* Variables and functions. */
40 .extern vTaskSwitchContext
41 .extern vApplicationIRQHandler
42 .extern vApplicationFPUSafeIRQHandler
43 .extern ulPortInterruptNesting
44 .extern ulPortTaskHasFPUContext
46 .extern ulPortYieldRequired
48 .global FreeRTOS_IRQ_Handler
49 .global FreeRTOS_SVC_Handler
50 .global vPortRestoreTaskContext
51 .global vPortInitialiseFPSCR
54 .global vPortEnableInterrupts
55 .global vPortDisableInterrupts
56 .global ulPortSetInterruptMaskFromISR
57 .global ulPortCountLeadingZeros
59 .weak vApplicationSVCHandler
60 /*-----------------------------------------------------------*/
62 .macro portSAVE_CONTEXT
64 /* Save the LR and SPSR onto the system mode stack before switching to
65 * system mode to save the remaining system mode registers. */
70 /* Push the critical nesting count. */
71 LDR R2, =ulCriticalNesting
75 /* Does the task have a floating point context that needs saving? If
76 * ulPortTaskHasFPUContext is 0 then no. */
77 LDR R2, =ulPortTaskHasFPUContext
81 /* Save the floating point context, if any. */
84 #if configFPU_D32 == 1
86 #endif /* configFPU_D32 */
89 /* Save ulPortTaskHasFPUContext itself. */
92 /* Save the stack pointer in the TCB. */
99 /*-----------------------------------------------------------*/
101 .macro portRESTORE_CONTEXT
103 /* Set the SP to point to the stack of the task being restored. */
104 LDR R0, =pxCurrentTCB
108 /* Is there a floating point context to restore? If the restored
109 * ulPortTaskHasFPUContext is zero then no. */
110 LDR R0, =ulPortTaskHasFPUContext
115 /* Restore the floating point context, if any. */
117 #if configFPU_D32 == 1
119 #endif /* configFPU_D32 */
123 /* Restore the critical section nesting depth. */
124 LDR R0, =ulCriticalNesting
128 /* Restore all system mode registers other than the SP (which is already
132 /* Return to the task code, loading CPSR on the way. */
137 /*-----------------------------------------------------------*/
140 * void vPortRestoreTaskContext( void );
142 * vPortRestoreTaskContext is used to start the scheduler.
145 .type vPortRestoreTaskContext, %function
146 vPortRestoreTaskContext:
147 /* Switch to system mode. */
151 /*-----------------------------------------------------------*/
154 * void vPortInitialiseFPSCR( void );
156 * vPortInitialiseFPSCR is used to initialize the FPSCR register.
159 .type vPortInitialiseFPSCR, %function
160 vPortInitialiseFPSCR:
165 /*-----------------------------------------------------------*/
168 * uint32_t ulReadAPSR( void );
170 * ulReadAPSR is used to read the value of APSR context.
173 .type ulReadAPSR, %function
178 /*-----------------------------------------------------------*/
181 * void vPortYield( void );
184 .type vPortYield, %function
190 /*-----------------------------------------------------------*/
193 * void vPortEnableInterrupts( void );
196 .type vPortEnableInterrupts, %function
197 vPortEnableInterrupts:
201 /*-----------------------------------------------------------*/
204 * void vPortDisableInterrupts( void );
207 .type vPortDisableInterrupts, %function
208 vPortDisableInterrupts:
214 /*-----------------------------------------------------------*/
217 * uint32_t ulPortSetInterruptMaskFromISR( void );
220 .type ulPortSetInterruptMaskFromISR, %function
221 ulPortSetInterruptMaskFromISR:
223 AND R0, R0, #CPSR_I_BIT
229 /*-----------------------------------------------------------*/
232 * void vApplicationSVCHandler( uint32_t ulSvcNumber );
235 .type vApplicationSVCHandler, %function
236 vApplicationSVCHandler:
237 B vApplicationSVCHandler
239 /*-----------------------------------------------------------*/
241 /* If the application provides an implementation of vApplicationIRQHandler(),
242 * then it will get called directly without saving the FPU registers on
243 * interrupt entry, and this weak implementation of vApplicationIRQHandler()
244 * will not get called.
246 * If the application provides its own implementation of
247 * vApplicationFPUSafeIRQHandler() then this implementation of
248 * vApplicationIRQHandler() will be called, save the FPU registers, and then
249 * call vApplicationFPUSafeIRQHandler().
251 * Therefore, if the application writer wants FPU registers to be saved on
252 * interrupt entry, their IRQ handler must be called
253 * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
254 * FPU registers to be saved on interrupt entry their IRQ handler must be
255 * called vApplicationIRQHandler().
258 .weak vApplicationIRQHandler
259 .type vApplicationIRQHandler, %function
260 vApplicationIRQHandler:
267 BLX vApplicationFPUSafeIRQHandler
275 /*-----------------------------------------------------------*/
278 .weak vApplicationFPUSafeIRQHandler
279 .type vApplicationFPUSafeIRQHandler, %function
280 vApplicationFPUSafeIRQHandler:
281 B vApplicationFPUSafeIRQHandler
283 /*-----------------------------------------------------------*/
286 * UBaseType_t ulPortCountLeadingZeros( UBaseType_t ulBitmap );
288 * According to the Procedure Call Standard for the ARM Architecture (AAPCS):
289 * - Parameter ulBitmap is passed in R0.
290 * - Return value must be in R0.
293 .type ulPortCountLeadingZeros, %function
294 ulPortCountLeadingZeros:
298 /*-----------------------------------------------------------*/
301 * SVC handler is used to yield.
304 .type FreeRTOS_SVC_Handler, %function
305 FreeRTOS_SVC_Handler:
308 /* ---------------------------- Get Caller SVC Number ---------------------------- */
309 MRS R0, SPSR /* R0 = CPSR at the time of SVC. */
310 TST R0, #0x20 /* Check Thumb bit (5) in CPSR. */
311 LDRHNE R0, [LR, #-0x2] /* If Thumb, load halfword. */
312 BICNE R0, R0, #0xFF00 /* And extract immidiate field (i.e. SVC number). */
313 LDREQ R0, [LR, #-0x4] /* If ARM, load word. */
314 BICEQ R0, R0, #0xFF000000 /* And extract immidiate field (i.e. SVC number). */
316 /* --------------------------------- SVC Routing --------------------------------- */
319 BNE svcApplicationCall
324 BLX vTaskSwitchContext
330 BLX vApplicationSVCHandler
333 /*-----------------------------------------------------------*/
336 .type FreeRTOS_IRQ_Handler, %function
337 FreeRTOS_IRQ_Handler:
338 /* Return to the interrupted instruction. */
341 /* Push the return address and SPSR. */
346 /* Change to supervisor mode to allow reentry. */
349 /* Push used registers. */
352 /* Increment nesting count. r3 holds the address of ulPortInterruptNesting
353 * for future use. r1 holds the original ulPortInterruptNesting value for
355 LDR R3, =ulPortInterruptNesting
360 /* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for
366 /* Call the interrupt handler. */
368 BLX vApplicationIRQHandler
372 /* Disable IRQs incase vApplicationIRQHandler enabled them for re-entry. */
377 /* Write to the EOI register. */
382 /* Restore the old nesting count. */
385 /* A context switch is never performed if the nesting count is not 0. */
387 BNE exit_without_switch
389 /* Did the interrupt request a context switch? r1 holds the address of
390 * ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
392 LDR R1, =ulPortYieldRequired
395 BNE switch_before_exit
398 /* No context switch. Restore used registers, LR_irq and SPSR before
408 /* A context switch is to be performed. Clear the context switch pending
413 /* Restore used registers, LR-irq and SPSR before saving the context
414 * to the task stack. */
422 /* Call the function that selects the new task to execute.
423 * vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD
424 * instructions, or 8 byte aligned stack allocated data. LR does not need
425 * saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */
426 BLX vTaskSwitchContext
428 /* Restore the context of, and branch to, the task selected to execute
432 /*-----------------------------------------------------------*/