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 /* Hardware registers. */ 37 .extern ulICCIAR 38 .extern ulICCEOIR 39 .extern ulICCPMR 40 41 /* Variables and functions. */ 42 .extern ulMaxAPIPriorityMask 43 .extern _freertos_vector_table 44 .extern pxCurrentTCB 45 .extern vTaskSwitchContext 46 .extern vApplicationIRQHandler 47 .extern ulPortInterruptNesting 48 49#if defined( __ARM_FP ) 50 .extern ulPortTaskHasFPUContext 51#endif /* __ARM_FP */ 52 53 .global FreeRTOS_IRQ_Handler 54 .global FreeRTOS_SWI_Handler 55 .global vPortRestoreTaskContext 56 57.macro portSAVE_CONTEXT 58 59 /* Save the LR and SPSR onto the system mode stack before switching to 60 system mode to save the remaining system mode registers. */ 61 SRSDB sp!, #SYS_MODE 62 CPS #SYS_MODE 63 PUSH {R0-R12, R14} 64 65 /* Push the critical nesting count. */ 66 LDR R2, ulCriticalNestingConst 67 LDR R1, [R2] 68 PUSH {R1} 69 70 #if defined( __ARM_FP ) 71 /* Does the task have a floating point context that needs saving? If 72 ulPortTaskHasFPUContext is 0 then no. */ 73 LDR R2, ulPortTaskHasFPUContextConst 74 LDR R3, [R2] 75 CMP R3, #0 76 77 /* Save the floating point context, if any. */ 78 FMRXNE R1, FPSCR 79 VPUSHNE {D0-D15} 80 PUSHNE {R1} 81 82 /* Save ulPortTaskHasFPUContext itself. */ 83 PUSH {R3} 84 #endif /* __ARM_FP */ 85 86 /* Save the stack pointer in the TCB. */ 87 LDR R0, pxCurrentTCBConst 88 LDR R1, [R0] 89 STR SP, [R1] 90 91 .endm 92 93; /**********************************************************************/ 94 95.macro portRESTORE_CONTEXT 96 97 /* Set the SP to point to the stack of the task being restored. */ 98 LDR R0, pxCurrentTCBConst 99 LDR R1, [R0] 100 LDR SP, [R1] 101 102 #if defined( __ARM_FP ) 103 /* 104 * Is there a floating point context to restore? If the restored 105 * ulPortTaskHasFPUContext is zero then no. 106 */ 107 LDR R0, ulPortTaskHasFPUContextConst 108 POP {R1} 109 STR R1, [R0] 110 CMP R1, #0 111 112 /* Restore the floating point context, if any. */ 113 POPNE {R0} 114 VPOPNE {D0-D15} 115 VMSRNE FPSCR, R0 116 #endif /* __ARM_FP */ 117 118 /* Restore the critical section nesting depth. */ 119 LDR R0, ulCriticalNestingConst 120 POP {R1} 121 STR R1, [R0] 122 123 /* Ensure the priority mask is correct for the critical nesting depth. */ 124 LDR R2, ulICCPMRConst 125 LDR R2, [R2] 126 CMP R1, #0 127 MOVEQ R4, #255 128 LDRNE R4, ulMaxAPIPriorityMaskConst 129 LDRNE R4, [R4] 130 STR R4, [R2] 131 132 /* Restore all system mode registers other than the SP (which is already 133 being used). */ 134 POP {R0-R12, R14} 135 136 /* Return to the task code, loading CPSR on the way. */ 137 RFEIA sp! 138 139 .endm 140 141 142/****************************************************************************** 143 * SVC handler is used to start the scheduler. 144 *****************************************************************************/ 145.align 4 146.type FreeRTOS_SWI_Handler, %function 147FreeRTOS_SWI_Handler: 148 /* Save the context of the current task and select a new task to run. */ 149 portSAVE_CONTEXT 150 LDR R0, vTaskSwitchContextConst 151 BLX R0 152 portRESTORE_CONTEXT 153 154 155/****************************************************************************** 156 * vPortRestoreTaskContext is used to start the scheduler. 157 *****************************************************************************/ 158.type vPortRestoreTaskContext, %function 159vPortRestoreTaskContext: 160 /* Switch to system mode. */ 161 CPS #SYS_MODE 162 portRESTORE_CONTEXT 163 164.align 4 165.type FreeRTOS_IRQ_Handler, %function 166FreeRTOS_IRQ_Handler: 167 168 /* Return to the interrupted instruction. */ 169 SUB lr, lr, #4 170 171 /* Push the return address and SPSR. */ 172 PUSH {lr} 173 MRS lr, SPSR 174 PUSH {lr} 175 176 /* Change to supervisor mode to allow reentry. */ 177 CPS #SVC_MODE 178 179 /* Push used registers. */ 180 PUSH {r0-r4, r12} 181 182 /* Increment nesting count. r3 holds the address of ulPortInterruptNesting 183 for future use. r1 holds the original ulPortInterruptNesting value for 184 future use. */ 185 LDR r3, ulPortInterruptNestingConst 186 LDR r1, [r3] 187 ADD r4, r1, #1 188 STR r4, [r3] 189 190 /* Read value from the interrupt acknowledge register, which is stored in r0 191 for future parameter and interrupt clearing use. */ 192 LDR r2, ulICCIARConst 193 LDR r2, [r2] 194 LDR r0, [r2] 195 196 /* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for 197 future use. _RB_ Is this ever needed provided the start of the stack is 198 alligned on an 8-byte boundary? */ 199 MOV r2, sp 200 AND r2, r2, #4 201 SUB sp, sp, r2 202 203 /* Call the interrupt handler. */ 204 PUSH {r0-r4, lr} 205 LDR r1, vApplicationIRQHandlerConst 206 BLX r1 207 POP {r0-r4, lr} 208 ADD sp, sp, r2 209 210 CPSID i 211 DSB 212 ISB 213 214 /* Write the value read from ICCIAR to ICCEOIR. */ 215 LDR r4, ulICCEOIRConst 216 LDR r4, [r4] 217 STR r0, [r4] 218 219 /* Restore the old nesting count. */ 220 STR r1, [r3] 221 222 /* A context switch is never performed if the nesting count is not 0. */ 223 CMP r1, #0 224 BNE exit_without_switch 225 226 /* Did the interrupt request a context switch? r1 holds the address of 227 ulPortYieldRequired and r0 the value of ulPortYieldRequired for future 228 use. */ 229 LDR r1, =ulPortYieldRequired 230 LDR r0, [r1] 231 CMP r0, #0 232 BNE switch_before_exit 233 234exit_without_switch: 235 /* No context switch. Restore used registers, LR_irq and SPSR before 236 returning. */ 237 POP {r0-r4, r12} 238 CPS #IRQ_MODE 239 POP {LR} 240 MSR SPSR_cxsf, LR 241 POP {LR} 242 MOVS PC, LR 243 244switch_before_exit: 245 /* A context swtich is to be performed. Clear the context switch pending 246 flag. */ 247 MOV r0, #0 248 STR r0, [r1] 249 250 /* Restore used registers, LR-irq and SPSR before saving the context 251 to the task stack. */ 252 POP {r0-r4, r12} 253 CPS #IRQ_MODE 254 POP {LR} 255 MSR SPSR_cxsf, LR 256 POP {LR} 257 portSAVE_CONTEXT 258 259 /* Call the function that selects the new task to execute. 260 vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD 261 instructions, or 8 byte aligned stack allocated data. LR does not need 262 saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */ 263 LDR R0, vTaskSwitchContextConst 264 BLX R0 265 266 /* Restore the context of, and branch to, the task selected to execute 267 next. */ 268 portRESTORE_CONTEXT 269 270/****************************************************************************** 271 * If the application provides an implementation of vApplicationIRQHandler(), 272 * then it will get called directly without saving the FPU registers on 273 * interrupt entry, and this weak implementation of 274 * vApplicationIRQHandler() will not get called. 275 * 276 * If the application provides its own implementation of 277 * vApplicationFPUSafeIRQHandler() then this implementation of 278 * vApplicationIRQHandler() will be called, save the FPU registers, and then 279 * call vApplicationFPUSafeIRQHandler(). 280 * 281 * Therefore, if the application writer wants FPU registers to be saved on 282 * interrupt entry their IRQ handler must be called 283 * vApplicationFPUSafeIRQHandler(), and if the application writer does not want 284 * FPU registers to be saved on interrupt entry their IRQ handler must be 285 * called vApplicationIRQHandler(). 286 *****************************************************************************/ 287.align 4 288.weak vApplicationIRQHandler 289.type vApplicationIRQHandler, %function 290vApplicationIRQHandler: 291 292 PUSH {LR} 293 294 #if defined( __ARM_FP ) 295 FMRX R1, FPSCR 296 VPUSH {D0-D15} 297 PUSH {R1} 298 299 LDR r1, vApplicationFPUSafeIRQHandlerConst 300 BLX r1 301 302 POP {R0} 303 VPOP {D0-D15} 304 VMSR FPSCR, R0 305 #endif /* __ARM_FP */ 306 307 POP {PC} 308 309ulICCIARConst: .word ulICCIAR 310ulICCEOIRConst: .word ulICCEOIR 311ulICCPMRConst: .word ulICCPMR 312pxCurrentTCBConst: .word pxCurrentTCB 313ulCriticalNestingConst: .word ulCriticalNesting 314 315#if defined( __ARM_FP ) 316 ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext 317 vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler 318#endif /* __ARM_FP */ 319 320ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask 321vTaskSwitchContextConst: .word vTaskSwitchContext 322vApplicationIRQHandlerConst: .word vApplicationIRQHandler 323ulPortInterruptNestingConst: .word ulPortInterruptNesting 324 325.end 326