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 31 /* Variables and functions. */ 32 .extern ullMaxAPIPriorityMask 33 .extern pxCurrentTCB 34 .extern vTaskSwitchContext 35 .extern vApplicationIRQHandler 36 .extern ullPortInterruptNesting 37 .extern ullPortTaskHasFPUContext 38 .extern ullCriticalNesting 39 .extern ullPortYieldRequired 40 .extern ullICCEOIR 41 .extern ullICCIAR 42 .extern _freertos_vector_table 43 44 .global FreeRTOS_IRQ_Handler 45 .global FreeRTOS_SWI_Handler 46 .global vPortRestoreTaskContext 47 48 49.macro portSAVE_CONTEXT 50 51 /* Switch to use the EL0 stack pointer. */ 52 MSR SPSEL, #0 53 54 /* Save the entire context. */ 55 STP X0, X1, [SP, #-0x10]! 56 STP X2, X3, [SP, #-0x10]! 57 STP X4, X5, [SP, #-0x10]! 58 STP X6, X7, [SP, #-0x10]! 59 STP X8, X9, [SP, #-0x10]! 60 STP X10, X11, [SP, #-0x10]! 61 STP X12, X13, [SP, #-0x10]! 62 STP X14, X15, [SP, #-0x10]! 63 STP X16, X17, [SP, #-0x10]! 64 STP X18, X19, [SP, #-0x10]! 65 STP X20, X21, [SP, #-0x10]! 66 STP X22, X23, [SP, #-0x10]! 67 STP X24, X25, [SP, #-0x10]! 68 STP X26, X27, [SP, #-0x10]! 69 STP X28, X29, [SP, #-0x10]! 70 STP X30, XZR, [SP, #-0x10]! 71 72 /* Save the SPSR. */ 73#if defined( GUEST ) 74 MRS X3, SPSR_EL1 75 MRS X2, ELR_EL1 76#else 77 MRS X3, SPSR_EL3 78 /* Save the ELR. */ 79 MRS X2, ELR_EL3 80#endif 81 82 STP X2, X3, [SP, #-0x10]! 83 84 /* Save the critical section nesting depth. */ 85 LDR X0, ullCriticalNestingConst 86 LDR X3, [X0] 87 88 /* Save the FPU context indicator. */ 89 LDR X0, ullPortTaskHasFPUContextConst 90 LDR X2, [X0] 91 92 /* Save the FPU context, if any (32 128-bit registers). */ 93 CMP X2, #0 94 B.EQ 1f 95 STP Q0, Q1, [SP,#-0x20]! 96 STP Q2, Q3, [SP,#-0x20]! 97 STP Q4, Q5, [SP,#-0x20]! 98 STP Q6, Q7, [SP,#-0x20]! 99 STP Q8, Q9, [SP,#-0x20]! 100 STP Q10, Q11, [SP,#-0x20]! 101 STP Q12, Q13, [SP,#-0x20]! 102 STP Q14, Q15, [SP,#-0x20]! 103 STP Q16, Q17, [SP,#-0x20]! 104 STP Q18, Q19, [SP,#-0x20]! 105 STP Q20, Q21, [SP,#-0x20]! 106 STP Q22, Q23, [SP,#-0x20]! 107 STP Q24, Q25, [SP,#-0x20]! 108 STP Q26, Q27, [SP,#-0x20]! 109 STP Q28, Q29, [SP,#-0x20]! 110 STP Q30, Q31, [SP,#-0x20]! 111 1121: 113 /* Store the critical nesting count and FPU context indicator. */ 114 STP X2, X3, [SP, #-0x10]! 115 116 LDR X0, pxCurrentTCBConst 117 LDR X1, [X0] 118 MOV X0, SP /* Move SP into X0 for saving. */ 119 STR X0, [X1] 120 121 /* Switch to use the ELx stack pointer. */ 122 MSR SPSEL, #1 123 124 .endm 125 126; /**********************************************************************/ 127 128.macro portRESTORE_CONTEXT 129 130 /* Switch to use the EL0 stack pointer. */ 131 MSR SPSEL, #0 132 133 /* Set the SP to point to the stack of the task being restored. */ 134 LDR X0, pxCurrentTCBConst 135 LDR X1, [X0] 136 LDR X0, [X1] 137 MOV SP, X0 138 139 LDP X2, X3, [SP], #0x10 /* Critical nesting and FPU context. */ 140 141 /* Set the PMR register to be correct for the current critical nesting 142 depth. */ 143 LDR X0, ullCriticalNestingConst /* X0 holds the address of ullCriticalNesting. */ 144 MOV X1, #255 /* X1 holds the unmask value. */ 145 LDR X4, ullICCPMRConst /* X4 holds the address of the ICCPMR constant. */ 146 CMP X3, #0 147 LDR X5, [X4] /* X5 holds the address of the ICCPMR register. */ 148 B.EQ 1f 149 LDR X6, ullMaxAPIPriorityMaskConst 150 LDR X1, [X6] /* X1 holds the mask value. */ 1511: 152 STR W1, [X5] /* Write the mask value to ICCPMR. */ 153 DSB SY /* _RB_Barriers probably not required here. */ 154 ISB SY 155 STR X3, [X0] /* Restore the task's critical nesting count. */ 156 157 /* Restore the FPU context indicator. */ 158 LDR X0, ullPortTaskHasFPUContextConst 159 STR X2, [X0] 160 161 /* Restore the FPU context, if any. */ 162 CMP X2, #0 163 B.EQ 1f 164 LDP Q30, Q31, [SP], #0x20 165 LDP Q28, Q29, [SP], #0x20 166 LDP Q26, Q27, [SP], #0x20 167 LDP Q24, Q25, [SP], #0x20 168 LDP Q22, Q23, [SP], #0x20 169 LDP Q20, Q21, [SP], #0x20 170 LDP Q18, Q19, [SP], #0x20 171 LDP Q16, Q17, [SP], #0x20 172 LDP Q14, Q15, [SP], #0x20 173 LDP Q12, Q13, [SP], #0x20 174 LDP Q10, Q11, [SP], #0x20 175 LDP Q8, Q9, [SP], #0x20 176 LDP Q6, Q7, [SP], #0x20 177 LDP Q4, Q5, [SP], #0x20 178 LDP Q2, Q3, [SP], #0x20 179 LDP Q0, Q1, [SP], #0x20 1801: 181 LDP X2, X3, [SP], #0x10 /* SPSR and ELR. */ 182 183#if defined( GUEST ) 184 /* Restore the SPSR. */ 185 MSR SPSR_EL1, X3 186 /* Restore the ELR. */ 187 MSR ELR_EL1, X2 188#else 189 /* Restore the SPSR. */ 190 MSR SPSR_EL3, X3 /*_RB_ Assumes started in EL3. */ 191 /* Restore the ELR. */ 192 MSR ELR_EL3, X2 193#endif 194 195 LDP X30, XZR, [SP], #0x10 196 LDP X28, X29, [SP], #0x10 197 LDP X26, X27, [SP], #0x10 198 LDP X24, X25, [SP], #0x10 199 LDP X22, X23, [SP], #0x10 200 LDP X20, X21, [SP], #0x10 201 LDP X18, X19, [SP], #0x10 202 LDP X16, X17, [SP], #0x10 203 LDP X14, X15, [SP], #0x10 204 LDP X12, X13, [SP], #0x10 205 LDP X10, X11, [SP], #0x10 206 LDP X8, X9, [SP], #0x10 207 LDP X6, X7, [SP], #0x10 208 LDP X4, X5, [SP], #0x10 209 LDP X2, X3, [SP], #0x10 210 LDP X0, X1, [SP], #0x10 211 212 /* Switch to use the ELx stack pointer. _RB_ Might not be required. */ 213 MSR SPSEL, #1 214 215 ERET 216 217 .endm 218 219 220/****************************************************************************** 221 * FreeRTOS_SWI_Handler handler is used to perform a context switch. 222 *****************************************************************************/ 223.align 8 224.type FreeRTOS_SWI_Handler, %function 225FreeRTOS_SWI_Handler: 226 /* Save the context of the current task and select a new task to run. */ 227 portSAVE_CONTEXT 228#if defined( GUEST ) 229 MRS X0, ESR_EL1 230#else 231 MRS X0, ESR_EL3 232#endif 233 234 LSR X1, X0, #26 235 236#if defined( GUEST ) 237 CMP X1, #0x15 /* 0x15 = SVC instruction. */ 238#else 239 CMP X1, #0x17 /* 0x17 = SMC instruction. */ 240#endif 241 B.NE FreeRTOS_Abort 242 BL vTaskSwitchContext 243 244 portRESTORE_CONTEXT 245 246FreeRTOS_Abort: 247 /* Full ESR is in X0, exception class code is in X1. */ 248 B . 249 250/****************************************************************************** 251 * vPortRestoreTaskContext is used to start the scheduler. 252 *****************************************************************************/ 253.align 8 254.type vPortRestoreTaskContext, %function 255vPortRestoreTaskContext: 256.set freertos_vector_base, _freertos_vector_table 257 258 /* Install the FreeRTOS interrupt handlers. */ 259 LDR X1, =freertos_vector_base 260#if defined( GUEST ) 261 MSR VBAR_EL1, X1 262#else 263 MSR VBAR_EL3, X1 264#endif 265 DSB SY 266 ISB SY 267 268 /* Start the first task. */ 269 portRESTORE_CONTEXT 270 271 272/****************************************************************************** 273 * FreeRTOS_IRQ_Handler handles IRQ entry and exit. 274 *****************************************************************************/ 275.align 8 276.type FreeRTOS_IRQ_Handler, %function 277FreeRTOS_IRQ_Handler: 278 /* Save volatile registers. */ 279 STP X0, X1, [SP, #-0x10]! 280 STP X2, X3, [SP, #-0x10]! 281 STP X4, X5, [SP, #-0x10]! 282 STP X6, X7, [SP, #-0x10]! 283 STP X8, X9, [SP, #-0x10]! 284 STP X10, X11, [SP, #-0x10]! 285 STP X12, X13, [SP, #-0x10]! 286 STP X14, X15, [SP, #-0x10]! 287 STP X16, X17, [SP, #-0x10]! 288 STP X18, X19, [SP, #-0x10]! 289 STP X29, X30, [SP, #-0x10]! 290 291 /* Save the SPSR and ELR. */ 292#if defined( GUEST ) 293 MRS X3, SPSR_EL1 294 MRS X2, ELR_EL1 295#else 296 MRS X3, SPSR_EL3 297 MRS X2, ELR_EL3 298#endif 299 STP X2, X3, [SP, #-0x10]! 300 301 /* Increment the interrupt nesting counter. */ 302 LDR X5, ullPortInterruptNestingConst 303 LDR X1, [X5] /* Old nesting count in X1. */ 304 ADD X6, X1, #1 305 STR X6, [X5] /* Address of nesting count variable in X5. */ 306 307 /* Maintain the interrupt nesting information across the function call. */ 308 STP X1, X5, [SP, #-0x10]! 309 310 /* Read value from the interrupt acknowledge register, which is stored in W0 311 for future parameter and interrupt clearing use. */ 312 LDR X2, ullICCIARConst 313 LDR X3, [X2] 314 LDR W0, [X3] /* ICCIAR in W0 as parameter. */ 315 316 /* Maintain the ICCIAR value across the function call. */ 317 STP X0, X1, [SP, #-0x10]! 318 319 /* Call the C handler. */ 320 BL vApplicationIRQHandler 321 322 /* Disable interrupts. */ 323 MSR DAIFSET, #2 324 DSB SY 325 ISB SY 326 327 /* Restore the ICCIAR value. */ 328 LDP X0, X1, [SP], #0x10 329 330 /* End IRQ processing by writing ICCIAR to the EOI register. */ 331 LDR X4, ullICCEOIRConst 332 LDR X4, [X4] 333 STR W0, [X4] 334 335 /* Restore the critical nesting count. */ 336 LDP X1, X5, [SP], #0x10 337 STR X1, [X5] 338 339 /* Has interrupt nesting unwound? */ 340 CMP X1, #0 341 B.NE Exit_IRQ_No_Context_Switch 342 343 /* Is a context switch required? */ 344 LDR X0, ullPortYieldRequiredConst 345 LDR X1, [X0] 346 CMP X1, #0 347 B.EQ Exit_IRQ_No_Context_Switch 348 349 /* Reset ullPortYieldRequired to 0. */ 350 MOV X2, #0 351 STR X2, [X0] 352 353 /* Restore volatile registers. */ 354 LDP X4, X5, [SP], #0x10 /* SPSR and ELR. */ 355#if defined( GUEST ) 356 MSR SPSR_EL1, X5 357 MSR ELR_EL1, X4 358#else 359 MSR SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */ 360 MSR ELR_EL3, X4 361#endif 362 DSB SY 363 ISB SY 364 365 LDP X29, X30, [SP], #0x10 366 LDP X18, X19, [SP], #0x10 367 LDP X16, X17, [SP], #0x10 368 LDP X14, X15, [SP], #0x10 369 LDP X12, X13, [SP], #0x10 370 LDP X10, X11, [SP], #0x10 371 LDP X8, X9, [SP], #0x10 372 LDP X6, X7, [SP], #0x10 373 LDP X4, X5, [SP], #0x10 374 LDP X2, X3, [SP], #0x10 375 LDP X0, X1, [SP], #0x10 376 377 /* Save the context of the current task and select a new task to run. */ 378 portSAVE_CONTEXT 379 BL vTaskSwitchContext 380 portRESTORE_CONTEXT 381 382Exit_IRQ_No_Context_Switch: 383 /* Restore volatile registers. */ 384 LDP X4, X5, [SP], #0x10 /* SPSR and ELR. */ 385#if defined( GUEST ) 386 MSR SPSR_EL1, X5 387 MSR ELR_EL1, X4 388#else 389 MSR SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */ 390 MSR ELR_EL3, X4 391#endif 392 DSB SY 393 ISB SY 394 395 LDP X29, X30, [SP], #0x10 396 LDP X18, X19, [SP], #0x10 397 LDP X16, X17, [SP], #0x10 398 LDP X14, X15, [SP], #0x10 399 LDP X12, X13, [SP], #0x10 400 LDP X10, X11, [SP], #0x10 401 LDP X8, X9, [SP], #0x10 402 LDP X6, X7, [SP], #0x10 403 LDP X4, X5, [SP], #0x10 404 LDP X2, X3, [SP], #0x10 405 LDP X0, X1, [SP], #0x10 406 407 ERET 408 409 410 411 412.align 8 413pxCurrentTCBConst: .dword pxCurrentTCB 414ullCriticalNestingConst: .dword ullCriticalNesting 415ullPortTaskHasFPUContextConst: .dword ullPortTaskHasFPUContext 416 417ullICCPMRConst: .dword ullICCPMR 418ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask 419ullPortInterruptNestingConst: .dword ullPortInterruptNesting 420ullPortYieldRequiredConst: .dword ullPortYieldRequired 421ullICCIARConst: .dword ullICCIAR 422ullICCEOIRConst: .dword ullICCEOIR 423vApplicationIRQHandlerConst: .word vApplicationIRQHandler 424 425 426 427.end 428