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 .eabi_attribute Tag_ABI_align_preserved, 1 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 .extern ulPortTaskHasFPUContext 49 50 .global FreeRTOS_IRQ_Handler 51 .global FreeRTOS_SWI_Handler 52 .global vPortRestoreTaskContext 53 54 55 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 /* Does the task have a floating point context that needs saving? If 71 ulPortTaskHasFPUContext is 0 then no. */ 72 LDR R2, ulPortTaskHasFPUContextConst 73 LDR R3, [R2] 74 CMP R3, #0 75 76 /* Save the floating point context, if any. */ 77 FMRXNE R1, FPSCR 78 PUSHNE {R1} 79 VPUSHNE {D0-D15} 80 VPUSHNE {D16-D31} 81 82 /* Save ulPortTaskHasFPUContext itself. */ 83 PUSH {R3} 84 85 /* Save the stack pointer in the TCB. */ 86 LDR R0, pxCurrentTCBConst 87 LDR R1, [R0] 88 STR SP, [R1] 89 90 .endm 91 92; /**********************************************************************/ 93 94.macro portRESTORE_CONTEXT 95 96 /* Set the SP to point to the stack of the task being restored. */ 97 LDR R0, pxCurrentTCBConst 98 LDR R1, [R0] 99 LDR SP, [R1] 100 101 /* Is there a floating point context to restore? If the restored 102 ulPortTaskHasFPUContext is zero then no. */ 103 LDR R0, ulPortTaskHasFPUContextConst 104 POP {R1} 105 STR R1, [R0] 106 CMP R1, #0 107 108 /* Restore the floating point context, if any. */ 109 VPOPNE {D16-D31} 110 VPOPNE {D0-D15} 111 POPNE {R0} 112 VMSRNE FPSCR, R0 113 114 /* Restore the critical section nesting depth. */ 115 LDR R0, ulCriticalNestingConst 116 POP {R1} 117 STR R1, [R0] 118 119 /* Ensure the priority mask is correct for the critical nesting depth. */ 120 LDR R2, ulICCPMRConst 121 LDR R2, [R2] 122 CMP R1, #0 123 MOVEQ R4, #255 124 LDRNE R4, ulMaxAPIPriorityMaskConst 125 LDRNE R4, [R4] 126 STR R4, [R2] 127 128 /* Restore all system mode registers other than the SP (which is already 129 being used). */ 130 POP {R0-R12, R14} 131 132 /* Return to the task code, loading CPSR on the way. */ 133 RFEIA sp! 134 135 .endm 136 137 138 139 140/****************************************************************************** 141 * SVC handler is used to start the scheduler. 142 *****************************************************************************/ 143.align 4 144.type FreeRTOS_SWI_Handler, %function 145FreeRTOS_SWI_Handler: 146 /* Save the context of the current task and select a new task to run. */ 147 portSAVE_CONTEXT 148 149 /* Ensure bit 2 of the stack pointer is clear. */ 150 MOV r2, sp 151 AND r2, r2, #4 152 SUB sp, sp, r2 153 154 LDR R0, vTaskSwitchContextConst 155 BLX R0 156 157 portRESTORE_CONTEXT 158 159 160/****************************************************************************** 161 * vPortRestoreTaskContext is used to start the scheduler. 162 *****************************************************************************/ 163.type vPortRestoreTaskContext, %function 164vPortRestoreTaskContext: 165 /* Switch to system mode. */ 166 CPS #SYS_MODE 167 portRESTORE_CONTEXT 168 169.align 4 170.type FreeRTOS_IRQ_Handler, %function 171FreeRTOS_IRQ_Handler: 172 /* Return to the interrupted instruction. */ 173 SUB lr, lr, #4 174 175 /* Push the return address and SPSR. */ 176 PUSH {lr} 177 MRS lr, SPSR 178 PUSH {lr} 179 180 /* Change to supervisor mode to allow reentry. */ 181 CPS #SVC_MODE 182 183 /* Push used registers. */ 184 PUSH {r0-r4, r12} 185 186 /* Increment nesting count. r3 holds the address of ulPortInterruptNesting 187 for future use. r1 holds the original ulPortInterruptNesting value for 188 future use. */ 189 LDR r3, ulPortInterruptNestingConst 190 LDR r1, [r3] 191 ADD r4, r1, #1 192 STR r4, [r3] 193 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 197 LDR r2, [r2] 198 LDR r0, [r2] 199 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? */ 203 MOV r2, sp 204 AND r2, r2, #4 205 SUB sp, sp, r2 206 207 /* Call the interrupt handler. r4 pushed to maintain alignment. */ 208 PUSH {r0-r4, lr} 209 LDR r1, vApplicationIRQHandlerConst 210 BLX r1 211 POP {r0-r4, lr} 212 ADD sp, sp, r2 213 214 CPSID i 215 DSB 216 ISB 217 218 /* Write the value read from ICCIAR to ICCEOIR. */ 219 LDR r4, ulICCEOIRConst 220 LDR r4, [r4] 221 STR r0, [r4] 222 223 /* Restore the old nesting count. */ 224 STR r1, [r3] 225 226 /* A context switch is never performed if the nesting count is not 0. */ 227 CMP r1, #0 228 BNE exit_without_switch 229 230 /* Did the interrupt request a context switch? r1 holds the address of 231 ulPortYieldRequired and r0 the value of ulPortYieldRequired for future 232 use. */ 233 LDR r1, =ulPortYieldRequired 234 LDR r0, [r1] 235 CMP r0, #0 236 BNE switch_before_exit 237 238exit_without_switch: 239 /* No context switch. Restore used registers, LR_irq and SPSR before 240 returning. */ 241 POP {r0-r4, r12} 242 CPS #IRQ_MODE 243 POP {LR} 244 MSR SPSR_cxsf, LR 245 POP {LR} 246 MOVS PC, LR 247 248switch_before_exit: 249 /* A context switch is to be performed. Clear the context switch pending 250 flag. */ 251 MOV r0, #0 252 STR r0, [r1] 253 254 /* Restore used registers, LR-irq and SPSR before saving the context 255 to the task stack. */ 256 POP {r0-r4, r12} 257 CPS #IRQ_MODE 258 POP {LR} 259 MSR SPSR_cxsf, LR 260 POP {LR} 261 portSAVE_CONTEXT 262 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 268 future use. */ 269 MOV r2, sp 270 AND r2, r2, #4 271 SUB sp, sp, r2 272 273 LDR R0, vTaskSwitchContextConst 274 BLX R0 275 276 /* Restore the context of, and branch to, the task selected to execute 277 next. */ 278 portRESTORE_CONTEXT 279 280 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. 286 * 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(). 291 * 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 *****************************************************************************/ 298 299.align 4 300.weak vApplicationIRQHandler 301.type vApplicationIRQHandler, %function 302vApplicationIRQHandler: 303 PUSH {LR} 304 FMRX R1, FPSCR 305 VPUSH {D0-D15} 306 VPUSH {D16-D31} 307 PUSH {R1} 308 309 LDR r1, vApplicationFPUSafeIRQHandlerConst 310 BLX r1 311 312 POP {R0} 313 VPOP {D16-D31} 314 VPOP {D0-D15} 315 VMSR FPSCR, R0 316 317 POP {PC} 318 319 320ulICCIARConst: .word ulICCIAR 321ulICCEOIRConst: .word ulICCEOIR 322ulICCPMRConst: .word ulICCPMR 323pxCurrentTCBConst: .word pxCurrentTCB 324ulCriticalNestingConst: .word ulCriticalNesting 325ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext 326ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask 327vTaskSwitchContextConst: .word vTaskSwitchContext 328vApplicationIRQHandlerConst: .word vApplicationIRQHandler 329ulPortInterruptNestingConst: .word ulPortInterruptNesting 330vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler 331 332.end 333