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 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 _freertos_vector_table 41 42 .global FreeRTOS_IRQ_Handler 43 .global FreeRTOS_SWI_Handler 44 .global vPortRestoreTaskContext 45 46 47.macro portSAVE_CONTEXT 48 49 /* Switch to use the EL0 stack pointer. */ 50 MSR SPSEL, #0 51 52 /* Save the entire context. */ 53 STP X0, X1, [SP, #-0x10]! 54 STP X2, X3, [SP, #-0x10]! 55 STP X4, X5, [SP, #-0x10]! 56 STP X6, X7, [SP, #-0x10]! 57 STP X8, X9, [SP, #-0x10]! 58 STP X10, X11, [SP, #-0x10]! 59 STP X12, X13, [SP, #-0x10]! 60 STP X14, X15, [SP, #-0x10]! 61 STP X16, X17, [SP, #-0x10]! 62 STP X18, X19, [SP, #-0x10]! 63 STP X20, X21, [SP, #-0x10]! 64 STP X22, X23, [SP, #-0x10]! 65 STP X24, X25, [SP, #-0x10]! 66 STP X26, X27, [SP, #-0x10]! 67 STP X28, X29, [SP, #-0x10]! 68 STP X30, XZR, [SP, #-0x10]! 69 70 /* Save the SPSR. */ 71#if defined( GUEST ) 72 MRS X3, SPSR_EL1 73 MRS X2, ELR_EL1 74#else 75 MRS X3, SPSR_EL3 76 /* Save the ELR. */ 77 MRS X2, ELR_EL3 78#endif 79 80 STP X2, X3, [SP, #-0x10]! 81 82 /* Save the critical section nesting depth. */ 83 LDR X0, ullCriticalNestingConst 84 LDR X3, [X0] 85 86 /* Save the FPU context indicator. */ 87 LDR X0, ullPortTaskHasFPUContextConst 88 LDR X2, [X0] 89 90 /* Save the FPU context, if any (32 128-bit registers). */ 91 CMP X2, #0 92 B.EQ 1f 93 STP Q0, Q1, [SP,#-0x20]! 94 STP Q2, Q3, [SP,#-0x20]! 95 STP Q4, Q5, [SP,#-0x20]! 96 STP Q6, Q7, [SP,#-0x20]! 97 STP Q8, Q9, [SP,#-0x20]! 98 STP Q10, Q11, [SP,#-0x20]! 99 STP Q12, Q13, [SP,#-0x20]! 100 STP Q14, Q15, [SP,#-0x20]! 101 STP Q16, Q17, [SP,#-0x20]! 102 STP Q18, Q19, [SP,#-0x20]! 103 STP Q20, Q21, [SP,#-0x20]! 104 STP Q22, Q23, [SP,#-0x20]! 105 STP Q24, Q25, [SP,#-0x20]! 106 STP Q26, Q27, [SP,#-0x20]! 107 STP Q28, Q29, [SP,#-0x20]! 108 STP Q30, Q31, [SP,#-0x20]! 109 1101: 111 /* Store the critical nesting count and FPU context indicator. */ 112 STP X2, X3, [SP, #-0x10]! 113 114 LDR X0, pxCurrentTCBConst 115 LDR X1, [X0] 116 MOV X0, SP /* Move SP into X0 for saving. */ 117 STR X0, [X1] 118 119 /* Switch to use the ELx stack pointer. */ 120 MSR SPSEL, #1 121 122 .endm 123 124; /**********************************************************************/ 125 126.macro portRESTORE_CONTEXT 127 128 /* Switch to use the EL0 stack pointer. */ 129 MSR SPSEL, #0 130 131 /* Set the SP to point to the stack of the task being restored. */ 132 LDR X0, pxCurrentTCBConst 133 LDR X1, [X0] 134 LDR X0, [X1] 135 MOV SP, X0 136 137 LDP X2, X3, [SP], #0x10 /* Critical nesting and FPU context. */ 138 139 /* Set the PMR register to be correct for the current critical nesting 140 depth. */ 141 LDR X0, ullCriticalNestingConst /* X0 holds the address of ullCriticalNesting. */ 142 MOV X1, #255 /* X1 holds the unmask value. */ 143 CMP X3, #0 144 B.EQ 1f 145 LDR X6, ullMaxAPIPriorityMaskConst 146 LDR X1, [X6] /* X1 holds the mask value. */ 1471: 148 MSR s3_0_c4_c6_0, X1 /* Write the mask value to ICCPMR. s3_0_c4_c6_0 is ICC_PMR_EL1. */ 149 DSB SY /* _RB_Barriers probably not required here. */ 150 ISB SY 151 STR X3, [X0] /* Restore the task's critical nesting count. */ 152 153 /* Restore the FPU context indicator. */ 154 LDR X0, ullPortTaskHasFPUContextConst 155 STR X2, [X0] 156 157 /* Restore the FPU context, if any. */ 158 CMP X2, #0 159 B.EQ 1f 160 LDP Q30, Q31, [SP], #0x20 161 LDP Q28, Q29, [SP], #0x20 162 LDP Q26, Q27, [SP], #0x20 163 LDP Q24, Q25, [SP], #0x20 164 LDP Q22, Q23, [SP], #0x20 165 LDP Q20, Q21, [SP], #0x20 166 LDP Q18, Q19, [SP], #0x20 167 LDP Q16, Q17, [SP], #0x20 168 LDP Q14, Q15, [SP], #0x20 169 LDP Q12, Q13, [SP], #0x20 170 LDP Q10, Q11, [SP], #0x20 171 LDP Q8, Q9, [SP], #0x20 172 LDP Q6, Q7, [SP], #0x20 173 LDP Q4, Q5, [SP], #0x20 174 LDP Q2, Q3, [SP], #0x20 175 LDP Q0, Q1, [SP], #0x20 1761: 177 LDP X2, X3, [SP], #0x10 /* SPSR and ELR. */ 178 179#if defined( GUEST ) 180 /* Restore the SPSR. */ 181 MSR SPSR_EL1, X3 182 /* Restore the ELR. */ 183 MSR ELR_EL1, X2 184#else 185 /* Restore the SPSR. */ 186 MSR SPSR_EL3, X3 /*_RB_ Assumes started in EL3. */ 187 /* Restore the ELR. */ 188 MSR ELR_EL3, X2 189#endif 190 191 LDP X30, XZR, [SP], #0x10 192 LDP X28, X29, [SP], #0x10 193 LDP X26, X27, [SP], #0x10 194 LDP X24, X25, [SP], #0x10 195 LDP X22, X23, [SP], #0x10 196 LDP X20, X21, [SP], #0x10 197 LDP X18, X19, [SP], #0x10 198 LDP X16, X17, [SP], #0x10 199 LDP X14, X15, [SP], #0x10 200 LDP X12, X13, [SP], #0x10 201 LDP X10, X11, [SP], #0x10 202 LDP X8, X9, [SP], #0x10 203 LDP X6, X7, [SP], #0x10 204 LDP X4, X5, [SP], #0x10 205 LDP X2, X3, [SP], #0x10 206 LDP X0, X1, [SP], #0x10 207 208 /* Switch to use the ELx stack pointer. _RB_ Might not be required. */ 209 MSR SPSEL, #1 210 211 ERET 212 213 .endm 214 215 216/****************************************************************************** 217 * FreeRTOS_SWI_Handler handler is used to perform a context switch. 218 *****************************************************************************/ 219.align 8 220.type FreeRTOS_SWI_Handler, %function 221FreeRTOS_SWI_Handler: 222 /* Save the context of the current task and select a new task to run. */ 223 portSAVE_CONTEXT 224#if defined( GUEST ) 225 MRS X0, ESR_EL1 226#else 227 MRS X0, ESR_EL3 228#endif 229 230 LSR X1, X0, #26 231 232#if defined( GUEST ) 233 CMP X1, #0x15 /* 0x15 = SVC instruction. */ 234#else 235 CMP X1, #0x17 /* 0x17 = SMC instruction. */ 236#endif 237 B.NE FreeRTOS_Abort 238 BL vTaskSwitchContext 239 240 portRESTORE_CONTEXT 241 242FreeRTOS_Abort: 243 /* Full ESR is in X0, exception class code is in X1. */ 244 B . 245 246/****************************************************************************** 247 * vPortRestoreTaskContext is used to start the scheduler. 248 *****************************************************************************/ 249.align 8 250.type vPortRestoreTaskContext, %function 251vPortRestoreTaskContext: 252.set freertos_vector_base, _freertos_vector_table 253 254 /* Install the FreeRTOS interrupt handlers. */ 255 LDR X1, =freertos_vector_base 256#if defined( GUEST ) 257 MSR VBAR_EL1, X1 258#else 259 MSR VBAR_EL3, X1 260#endif 261 DSB SY 262 ISB SY 263 264 /* Start the first task. */ 265 portRESTORE_CONTEXT 266 267 268/****************************************************************************** 269 * FreeRTOS_IRQ_Handler handles IRQ entry and exit. 270 271 * This handler is supposed to be used only for IRQs and never for FIQs. Per ARM 272 * GIC documentation [1], Group 0 interrupts are always signaled as FIQs. Since 273 * this handler is only for IRQs, We can safely assume Group 1 while accessing 274 * Interrupt Acknowledge and End Of Interrupt registers and therefore, use 275 * ICC_IAR1_EL1 and ICC_EOIR1_EL1. 276 * 277 * [1] https://developer.arm.com/documentation/198123/0300/Arm-CoreLink-GIC-fundamentals 278 *****************************************************************************/ 279.align 8 280.type FreeRTOS_IRQ_Handler, %function 281FreeRTOS_IRQ_Handler: 282 /* Save volatile registers. */ 283 STP X0, X1, [SP, #-0x10]! 284 STP X2, X3, [SP, #-0x10]! 285 STP X4, X5, [SP, #-0x10]! 286 STP X6, X7, [SP, #-0x10]! 287 STP X8, X9, [SP, #-0x10]! 288 STP X10, X11, [SP, #-0x10]! 289 STP X12, X13, [SP, #-0x10]! 290 STP X14, X15, [SP, #-0x10]! 291 STP X16, X17, [SP, #-0x10]! 292 STP X18, X19, [SP, #-0x10]! 293 STP X29, X30, [SP, #-0x10]! 294 295 /* Save the SPSR and ELR. */ 296#if defined( GUEST ) 297 MRS X3, SPSR_EL1 298 MRS X2, ELR_EL1 299#else 300 MRS X3, SPSR_EL3 301 MRS X2, ELR_EL3 302#endif 303 STP X2, X3, [SP, #-0x10]! 304 305 /* Increment the interrupt nesting counter. */ 306 LDR X5, ullPortInterruptNestingConst 307 LDR X1, [X5] /* Old nesting count in X1. */ 308 ADD X6, X1, #1 309 STR X6, [X5] /* Address of nesting count variable in X5. */ 310 311 /* Maintain the interrupt nesting information across the function call. */ 312 STP X1, X5, [SP, #-0x10]! 313 314 /* Read interrupt ID from the interrupt acknowledge register and store it 315 in X0 for future parameter and interrupt clearing use. */ 316 MRS X0, S3_0_C12_C12_0 /* S3_0_C12_C12_0 is ICC_IAR1_EL1. */ 317 318 /* Maintain the interrupt ID value across the function call. */ 319 STP X0, X1, [SP, #-0x10]! 320 321 /* Call the C handler. */ 322 BL vApplicationIRQHandler 323 324 /* Disable interrupts. */ 325 MSR DAIFSET, #2 326 DSB SY 327 ISB SY 328 329 /* Restore the interrupt ID value. */ 330 LDP X0, X1, [SP], #0x10 331 332 /* End IRQ processing by writing interrupt ID value to the EOI register. */ 333 MSR S3_0_C12_C12_1, X0 /* S3_0_C12_C12_1 is ICC_EOIR1_EL1. */ 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 417ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask 418ullPortInterruptNestingConst: .dword ullPortInterruptNesting 419ullPortYieldRequiredConst: .dword ullPortYieldRequired 420 421.end 422