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 .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 PUSHNE {R1} 80 VPUSHNE {D0-D15} 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 VPOPNE {D0-D15} 114 POPNE {R0} 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 151 /* Ensure bit 2 of the stack pointer is clear. */ 152 MOV r2, sp 153 AND r2, r2, #4 154 SUB sp, sp, r2 155 156 LDR R0, vTaskSwitchContextConst 157 BLX R0 158 159 portRESTORE_CONTEXT 160 161 162/****************************************************************************** 163 * vPortRestoreTaskContext is used to start the scheduler. 164 *****************************************************************************/ 165.type vPortRestoreTaskContext, %function 166vPortRestoreTaskContext: 167 /* Switch to system mode. */ 168 CPS #SYS_MODE 169 portRESTORE_CONTEXT 170 171.align 4 172.type FreeRTOS_IRQ_Handler, %function 173FreeRTOS_IRQ_Handler: 174 175 /* Return to the interrupted instruction. */ 176 SUB lr, lr, #4 177 178 /* Push the return address and SPSR. */ 179 PUSH {lr} 180 MRS lr, SPSR 181 PUSH {lr} 182 183 /* Change to supervisor mode to allow reentry. */ 184 CPS #SVC_MODE 185 186 /* Push used registers. */ 187 PUSH {r0-r4, r12} 188 189 /* Increment nesting count. r3 holds the address of ulPortInterruptNesting 190 for future use. r1 holds the original ulPortInterruptNesting value for 191 future use. */ 192 LDR r3, ulPortInterruptNestingConst 193 LDR r1, [r3] 194 ADD r4, r1, #1 195 STR r4, [r3] 196 197 /* Read value from the interrupt acknowledge register, which is stored in r0 198 for future parameter and interrupt clearing use. */ 199 LDR r2, ulICCIARConst 200 LDR r2, [r2] 201 LDR r0, [r2] 202 203 /* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for 204 future use. _RB_ Is this ever needed provided the start of the stack is 205 alligned on an 8-byte boundary? */ 206 MOV r2, sp 207 AND r2, r2, #4 208 SUB sp, sp, r2 209 210 /* Call the interrupt handler. */ 211 PUSH {r0-r4, lr} 212 LDR r1, vApplicationIRQHandlerConst 213 BLX r1 214 POP {r0-r4, lr} 215 ADD sp, sp, r2 216 217 CPSID i 218 DSB 219 ISB 220 221 /* Write the value read from ICCIAR to ICCEOIR. */ 222 LDR r4, ulICCEOIRConst 223 LDR r4, [r4] 224 STR r0, [r4] 225 226 /* Restore the old nesting count. */ 227 STR r1, [r3] 228 229 /* A context switch is never performed if the nesting count is not 0. */ 230 CMP r1, #0 231 BNE exit_without_switch 232 233 /* Did the interrupt request a context switch? r1 holds the address of 234 ulPortYieldRequired and r0 the value of ulPortYieldRequired for future 235 use. */ 236 LDR r1, =ulPortYieldRequired 237 LDR r0, [r1] 238 CMP r0, #0 239 BNE switch_before_exit 240 241exit_without_switch: 242 /* No context switch. Restore used registers, LR_irq and SPSR before 243 returning. */ 244 POP {r0-r4, r12} 245 CPS #IRQ_MODE 246 POP {LR} 247 MSR SPSR_cxsf, LR 248 POP {LR} 249 MOVS PC, LR 250 251switch_before_exit: 252 /* A context switch is to be performed. Clear the context switch pending 253 flag. */ 254 MOV r0, #0 255 STR r0, [r1] 256 257 /* Restore used registers, LR-irq and SPSR before saving the context 258 to the task stack. */ 259 POP {r0-r4, r12} 260 CPS #IRQ_MODE 261 POP {LR} 262 MSR SPSR_cxsf, LR 263 POP {LR} 264 portSAVE_CONTEXT 265 266 /* Ensure bit 2 of the stack pointer is clear. */ 267 MOV r2, sp 268 AND r2, r2, #4 269 SUB sp, sp, r2 270 271 /* Call the function that selects the new task to execute. 272 vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD 273 instructions, or 8 byte aligned stack allocated data. LR does not need 274 saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */ 275 LDR R0, vTaskSwitchContextConst 276 BLX R0 277 278 /* Restore the context of, and branch to, the task selected to execute 279 next. */ 280 portRESTORE_CONTEXT 281 282/****************************************************************************** 283 * If the application provides an implementation of vApplicationIRQHandler(), 284 * then it will get called directly without saving the FPU registers on 285 * interrupt entry, and this weak implementation of 286 * vApplicationIRQHandler() will not get called. 287 * 288 * If the application provides its own implementation of 289 * vApplicationFPUSafeIRQHandler() then this implementation of 290 * vApplicationIRQHandler() will be called, save the FPU registers, and then 291 * call vApplicationFPUSafeIRQHandler(). 292 * 293 * Therefore, if the application writer wants FPU registers to be saved on 294 * interrupt entry their IRQ handler must be called 295 * vApplicationFPUSafeIRQHandler(), and if the application writer does not want 296 * FPU registers to be saved on interrupt entry their IRQ handler must be 297 * called vApplicationIRQHandler(). 298 *****************************************************************************/ 299.align 4 300.weak vApplicationIRQHandler 301.type vApplicationIRQHandler, %function 302vApplicationIRQHandler: 303 304 PUSH {LR} 305 306 #if defined( __ARM_FP ) 307 FMRX R1, FPSCR 308 VPUSH {D0-D15} 309 PUSH {R1} 310 311 LDR r1, vApplicationFPUSafeIRQHandlerConst 312 BLX r1 313 314 POP {R0} 315 VPOP {D0-D15} 316 VMSR FPSCR, R0 317 #endif /* __ARM_FP */ 318 319 POP {PC} 320 321ulICCIARConst: .word ulICCIAR 322ulICCEOIRConst: .word ulICCEOIR 323ulICCPMRConst: .word ulICCPMR 324pxCurrentTCBConst: .word pxCurrentTCB 325ulCriticalNestingConst: .word ulCriticalNesting 326 327#if defined( __ARM_FP ) 328 ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext 329 vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler 330#endif /* __ARM_FP */ 331 332ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask 333vTaskSwitchContextConst: .word vTaskSwitchContext 334vApplicationIRQHandlerConst: .word vApplicationIRQHandler 335ulPortInterruptNestingConst: .word ulPortInterruptNesting 336 337.end 338