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 /* Variables and functions. */ 37 .extern ulMaxAPIPriorityMask 38 .extern _freertos_vector_table 39 .extern pxCurrentTCB 40 .extern vTaskSwitchContext 41 .extern vApplicationIRQHandler 42 .extern ulPortInterruptNesting 43 .extern ulPortTaskHasFPUContext 44 .extern ulICCEOIR 45 .extern ulPortYieldRequired 46 47 .global FreeRTOS_IRQ_Handler 48 .global FreeRTOS_SVC_Handler 49 .global vPortRestoreTaskContext 50 51 52.macro portSAVE_CONTEXT 53 54 /* Save the LR and SPSR onto the system mode stack before switching to 55 system mode to save the remaining system mode registers. */ 56 SRSDB sp!, #SYS_MODE 57 CPS #SYS_MODE 58 PUSH {R0-R12, R14} 59 60 /* Push the critical nesting count. */ 61 LDR R2, ulCriticalNestingConst 62 LDR R1, [R2] 63 PUSH {R1} 64 65 /* Does the task have a floating point context that needs saving? If 66 ulPortTaskHasFPUContext is 0 then no. */ 67 LDR R2, ulPortTaskHasFPUContextConst 68 LDR R3, [R2] 69 CMP R3, #0 70 71 /* Save the floating point context, if any. */ 72 FMRXNE R1, FPSCR 73 VPUSHNE {D0-D15} 74#if configFPU_D32 == 1 75 VPUSHNE {D16-D31} 76#endif /* configFPU_D32 */ 77 PUSHNE {R1} 78 79 /* Save ulPortTaskHasFPUContext itself. */ 80 PUSH {R3} 81 82 /* Save the stack pointer in the TCB. */ 83 LDR R0, pxCurrentTCBConst 84 LDR R1, [R0] 85 STR SP, [R1] 86 87 .endm 88 89; /**********************************************************************/ 90 91.macro portRESTORE_CONTEXT 92 93 /* Set the SP to point to the stack of the task being restored. */ 94 LDR R0, pxCurrentTCBConst 95 LDR R1, [R0] 96 LDR SP, [R1] 97 98 /* Is there a floating point context to restore? If the restored 99 ulPortTaskHasFPUContext is zero then no. */ 100 LDR R0, ulPortTaskHasFPUContextConst 101 POP {R1} 102 STR R1, [R0] 103 CMP R1, #0 104 105 /* Restore the floating point context, if any. */ 106 POPNE {R0} 107#if configFPU_D32 == 1 108 VPOPNE {D16-D31} 109#endif /* configFPU_D32 */ 110 VPOPNE {D0-D15} 111 VMSRNE FPSCR, R0 112 113 /* Restore the critical section nesting depth. */ 114 LDR R0, ulCriticalNestingConst 115 POP {R1} 116 STR R1, [R0] 117 118 /* Restore all system mode registers other than the SP (which is already 119 being used). */ 120 POP {R0-R12, R14} 121 122 /* Return to the task code, loading CPSR on the way. */ 123 RFEIA sp! 124 125 .endm 126 127 128 129 130/****************************************************************************** 131 * SVC handler is used to yield. 132 *****************************************************************************/ 133.align 4 134.type FreeRTOS_SVC_Handler, %function 135FreeRTOS_SVC_Handler: 136 /* Save the context of the current task and select a new task to run. */ 137 portSAVE_CONTEXT 138 LDR R0, vTaskSwitchContextConst 139 BLX R0 140 portRESTORE_CONTEXT 141 142 143/****************************************************************************** 144 * vPortRestoreTaskContext is used to start the scheduler. 145 *****************************************************************************/ 146.align 4 147.type vPortRestoreTaskContext, %function 148vPortRestoreTaskContext: 149 /* Switch to system mode. */ 150 CPS #SYS_MODE 151 portRESTORE_CONTEXT 152 153.align 4 154.type FreeRTOS_IRQ_Handler, %function 155FreeRTOS_IRQ_Handler: 156 /* Return to the interrupted instruction. */ 157 SUB lr, lr, #4 158 159 /* Push the return address and SPSR. */ 160 PUSH {lr} 161 MRS lr, SPSR 162 PUSH {lr} 163 164 /* Change to supervisor mode to allow reentry. */ 165 CPS #0x13 166 167 /* Push used registers. */ 168 PUSH {r0-r3, r12} 169 170 /* Increment nesting count. r3 holds the address of ulPortInterruptNesting 171 for future use. r1 holds the original ulPortInterruptNesting value for 172 future use. */ 173 LDR r3, ulPortInterruptNestingConst 174 LDR r1, [r3] 175 ADD r0, r1, #1 176 STR r0, [r3] 177 178 /* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for 179 future use. */ 180 MOV r0, sp 181 AND r2, r0, #4 182 SUB sp, sp, r2 183 184 /* Call the interrupt handler. */ 185 PUSH {r0-r3, lr} 186 LDR r1, vApplicationIRQHandlerConst 187 BLX r1 188 POP {r0-r3, lr} 189 ADD sp, sp, r2 190 191 CPSID i 192 DSB 193 ISB 194 195 /* Write to the EOI register. */ 196 LDR r0, ulICCEOIRConst 197 LDR r2, [r0] 198 STR r0, [r2] 199 200 /* Restore the old nesting count. */ 201 STR r1, [r3] 202 203 /* A context switch is never performed if the nesting count is not 0. */ 204 CMP r1, #0 205 BNE exit_without_switch 206 207 /* Did the interrupt request a context switch? r1 holds the address of 208 ulPortYieldRequired and r0 the value of ulPortYieldRequired for future 209 use. */ 210 LDR r1, ulPortYieldRequiredConst 211 LDR r0, [r1] 212 CMP r0, #0 213 BNE switch_before_exit 214 215exit_without_switch: 216 /* No context switch. Restore used registers, LR_irq and SPSR before 217 returning. */ 218 POP {r0-r3, r12} 219 CPS #IRQ_MODE 220 POP {LR} 221 MSR SPSR_cxsf, LR 222 POP {LR} 223 MOVS PC, LR 224 225switch_before_exit: 226 /* A context swtich is to be performed. Clear the context switch pending 227 flag. */ 228 MOV r0, #0 229 STR r0, [r1] 230 231 /* Restore used registers, LR-irq and SPSR before saving the context 232 to the task stack. */ 233 POP {r0-r3, r12} 234 CPS #IRQ_MODE 235 POP {LR} 236 MSR SPSR_cxsf, LR 237 POP {LR} 238 portSAVE_CONTEXT 239 240 /* Call the function that selects the new task to execute. 241 vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD 242 instructions, or 8 byte aligned stack allocated data. LR does not need 243 saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */ 244 LDR R0, vTaskSwitchContextConst 245 BLX R0 246 247 /* Restore the context of, and branch to, the task selected to execute 248 next. */ 249 portRESTORE_CONTEXT 250 251ulICCEOIRConst: .word ulICCEOIR 252pxCurrentTCBConst: .word pxCurrentTCB 253ulCriticalNestingConst: .word ulCriticalNesting 254ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext 255vTaskSwitchContextConst: .word vTaskSwitchContext 256vApplicationIRQHandlerConst: .word vApplicationIRQHandler 257ulPortInterruptNestingConst: .word ulPortInterruptNesting 258ulPortYieldRequiredConst: .word ulPortYieldRequired 259 260.end 261