| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159 |
- /*
- * FreeRTOS Kernel <DEVELOPMENT BRANCH>
- * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- * Copyright 2025-2026 Arm Limited and/or its affiliates
- * <open-source-office@arm.com>
- *
- * SPDX-License-Identifier: MIT
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * https://www.FreeRTOS.org
- * https://github.com/FreeRTOS
- *
- */
- /*
- * This file is tailored for ARM Cortex-R82 with SMP enabled.
- * It includes macros and functions for saving/restoring task context,
- * handling interrupts, and supporting multi-core operations.
- */
- #include "FreeRTOSConfig.h"
- #include "portmacro.h"
- /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE ensures that PRIVILEGED_FUNCTION
- * is defined correctly and privileged functions are placed in correct sections. */
- #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
- /* System call numbers includes. */
- #include "mpu_syscall_numbers.h"
- /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE is needed to be defined only for the
- * header files. */
- #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
- .text
- /* Variables and functions. */
- #if ( configNUMBER_OF_CORES == 1 )
- .extern pxCurrentTCB
- .extern ullCriticalNesting
- .extern ullPortInterruptNesting
- #else /* #if ( configNUMBER_OF_CORES == 1 ) */
- .extern pxCurrentTCBs
- .extern ullCriticalNestings
- .extern ullPortInterruptNestings
- #endif
- .extern vTaskSwitchContext
- .extern vApplicationIRQHandler
- .extern ullPortTaskHasFPUContext
- .extern ullPortYieldRequired
- .extern _freertos_vector_table
- #if ( configENABLE_MPU == 1 )
- .extern xPortIsTaskPrivileged
- .extern vSystemCallEnter
- .extern vSystemCallExit
- .extern vRequestSystemCallExit
- .extern uxSystemCallImplementations
- #endif /* #if ( configENABLE_MPU == 1 ) */
- .global FreeRTOS_IRQ_Handler
- .global FreeRTOS_SWI_Handler
- .global vPortSaveTaskContext
- .global vPortRestoreTaskContext
- #if ( configENABLE_MPU == 1 )
- .macro portLOAD_MPU_REGIONS_ADDRESSES
- MOV X3, # portSTACK_REGION /* Task's first programmed region is its stack region as the first four MPU regions are already programmed.*/
- MOV X4, # configTOTAL_MPU_REGIONS - 1 /* Upper limit = configTOTAL_MPU_REGIONS - 1 */
- 1 :
- CMP X3, X4 /* Compare i with ( configTOTAL_MPU_REGIONS - 1 ) */
- B.GT 2f /* if i > ( configTOTAL_MPU_REGIONS - 1 ), exit loop */
- MSR PRSELR_EL1, X3 /* Program PRSELR_EL1. */
- ISB /* Ensure PRSELR selection takes effect before registers access. */
- LDP X1, X2, [ X0 ], # 0x10 /* Retrieve ullPrbarEl1 and ullPrlarEl1r */
- MSR PRBAR_EL1, X1 /* Program PRBAR_EL1. */
- MSR PRLAR_EL1, X2 /* Program PRLAR_EL1. */
- ADD X3, X3, # 1 /* i++ */
- B 1b
- 2 :
- DSB SY
- ISB
- .endm
- .macro portSTORE_MPU_REGIONS_ADDRESSES
- MOV X3, # portSTACK_REGION /* Task's first programmed region is its stack region as the first four MPU regions are already programmed.*/
- MOV X4, # configTOTAL_MPU_REGIONS - 1 /* Upper limit = configTOTAL_MPU_REGIONS - 1 */
- 1 :
- CMP X3, X4 /* Compare i with ( configTOTAL_MPU_REGIONS - 1 ) */
- B.GT 2f /* if i > ( configTOTAL_MPU_REGIONS - 1 ), exit loop */
- MSR PRSELR_EL1, X3 /* Program PRSELR_EL1. */
- ISB /* Ensure PRSELR selection takes effect before registers access. */
- MRS X1, PRBAR_EL1 /* Retrieve PRBAR_EL1. */
- MRS X2, PRLAR_EL1 /* Retrieve PRLAR_EL1. */
- STP X1, X2, [ X0 ], # 0x10 /* Store PRBAR_EL1 and PRLAR_EL1 in ullPrbarEl1 and ullPrlarEl1r */
- ADD X3, X3, # 1 /* i++ */
- B 1b
- 2 :
- /* No additional barrier required after reading PR* registers. */
- .endm
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /*-----------------------------------------------------------*/
- .macro savefuncontextgpregs
- /* Save function context general-purpose registers. */
- STP X0, X1, [ SP, # - 0x10 ] !
- STP X2, X3, [ SP, # - 0x10 ] !
- STP X4, X5, [ SP, # - 0x10 ] !
- STP X6, X7, [ SP, # - 0x10 ] !
- STP X8, X9, [ SP, # - 0x10 ] !
- STP X10, X11, [ SP, # - 0x10 ] !
- STP X12, X13, [ SP, # - 0x10 ] !
- STP X14, X15, [ SP, # - 0x10 ] !
- STP X16, X17, [ SP, # - 0x10 ] !
- STP X18, X29, [ SP, # - 0x10 ] !
- STR X30, [ SP, # - 0x10 ] !
- .endm
- /*-----------------------------------------------------------*/
- .macro savesyscallcontextgpregs
- /* Save system call context general-purpose registers. */
- STP X4, X5, [ SP, # - 0x10 ] !
- STP X6, X7, [ SP, # - 0x10 ] !
- STP X8, X9, [ SP, # - 0x10 ] !
- STP X10, X11, [ SP, # - 0x10 ] !
- STP X12, X13, [ SP, # - 0x10 ] !
- STP X14, X15, [ SP, # - 0x10 ] !
- STP X16, X17, [ SP, # - 0x10 ] !
- STP X18, X29, [ SP, # - 0x10 ] !
- .endm
- /*-----------------------------------------------------------*/
- .macro restorefuncontextgpregs
- /* Restore function context general-purpose registers. */
- LDR X30, [ SP ], # 0x10
- LDP X18, X29, [ SP ], # 0x10
- LDP X16, X17, [ SP ], # 0x10
- LDP X14, X15, [ SP ], # 0x10
- LDP X12, X13, [ SP ], # 0x10
- LDP X10, X11, [ SP ], # 0x10
- LDP X8, X9, [ SP ], # 0x10
- LDP X6, X7, [ SP ], # 0x10
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- .endm
- /*-----------------------------------------------------------*/
- .macro restorefuncontextgpregexceptx0
- /* Restore function context general-purpose registers while discarding old X0. */
- LDR X30, [ SP ], # 0x10
- LDP X18, X29, [ SP ], # 0x10
- LDP X16, X17, [ SP ], # 0x10
- LDP X14, X15, [ SP ], # 0x10
- LDP X12, X13, [ SP ], # 0x10
- LDP X10, X11, [ SP ], # 0x10
- LDP X8, X9, [ SP ], # 0x10
- LDP X6, X7, [ SP ], # 0x10
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP XZR, X1, [ SP ], # 0x10
- .endm
- /*-----------------------------------------------------------*/
- .macro restoresyscallcontextgpregs
- /* Restore system call context general-purpose registers. */
- LDP X18, X29, [ SP ], # 0x10
- LDP X16, X17, [ SP ], # 0x10
- LDP X14, X15, [ SP ], # 0x10
- LDP X12, X13, [ SP ], # 0x10
- LDP X10, X11, [ SP ], # 0x10
- LDP X8, X9, [ SP ], # 0x10
- LDP X6, X7, [ SP ], # 0x10
- LDP X4, X5, [ SP ], # 0x10
- .endm
- /*-----------------------------------------------------------*/
- .macro saveallgpregisters
- /* Save all general-purpose registers on stack. */
- STP X0, X1, [ SP, # - 0x10 ] !
- STP X2, X3, [ SP, # - 0x10 ] !
- STP X4, X5, [ SP, # - 0x10 ] !
- STP X6, X7, [ SP, # - 0x10 ] !
- STP X8, X9, [ SP, # - 0x10 ] !
- STP X10, X11, [ SP, # - 0x10 ] !
- STP X12, X13, [ SP, # - 0x10 ] !
- STP X14, X15, [ SP, # - 0x10 ] !
- STP X16, X17, [ SP, # - 0x10 ] !
- STP X18, X19, [ SP, # - 0x10 ] !
- STP X20, X21, [ SP, # - 0x10 ] !
- STP X22, X23, [ SP, # - 0x10 ] !
- STP X24, X25, [ SP, # - 0x10 ] !
- STP X26, X27, [ SP, # - 0x10 ] !
- STP X28, X29, [ SP, # - 0x10 ] !
- STP X30, XZR, [ SP, # - 0x10 ] !
- .endm
- /*-----------------------------------------------------------*/
- .macro restoreallgpregisters
- /* Restore all general-purpose registers from stack. */
- LDP X30, XZR, [ SP ], # 0x10
- LDP X28, X29, [ SP ], # 0x10
- LDP X26, X27, [ SP ], # 0x10
- LDP X24, X25, [ SP ], # 0x10
- LDP X22, X23, [ SP ], # 0x10
- LDP X20, X21, [ SP ], # 0x10
- LDP X18, X19, [ SP ], # 0x10
- LDP X16, X17, [ SP ], # 0x10
- LDP X14, X15, [ SP ], # 0x10
- LDP X12, X13, [ SP ], # 0x10
- LDP X10, X11, [ SP ], # 0x10
- LDP X8, X9, [ SP ], # 0x10
- LDP X6, X7, [ SP ], # 0x10
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- .endm
- /*-----------------------------------------------------------*/
- .macro savefloatregisters
- /* Save floating-point registers and configuration/status registers. */
- STP Q0, Q1, [ SP, # - 0x20 ] !
- STP Q2, Q3, [ SP, # - 0x20 ] !
- STP Q4, Q5, [ SP, # - 0x20 ] !
- STP Q6, Q7, [ SP, # - 0x20 ] !
- STP Q8, Q9, [ SP, # - 0x20 ] !
- STP Q10, Q11, [ SP, # - 0x20 ] !
- STP Q12, Q13, [ SP, # - 0x20 ] !
- STP Q14, Q15, [ SP, # - 0x20 ] !
- STP Q16, Q17, [ SP, # - 0x20 ] !
- STP Q18, Q19, [ SP, # - 0x20 ] !
- STP Q20, Q21, [ SP, # - 0x20 ] !
- STP Q22, Q23, [ SP, # - 0x20 ] !
- STP Q24, Q25, [ SP, # - 0x20 ] !
- STP Q26, Q27, [ SP, # - 0x20 ] !
- STP Q28, Q29, [ SP, # - 0x20 ] !
- STP Q30, Q31, [ SP, # - 0x20 ] !
- MRS X9, FPSR
- MRS X10, FPCR
- STP W9, W10, [ SP, # - 0x10 ] !
- .endm
- /*-----------------------------------------------------------*/
- .macro restorefloatregisters
- /* Restore floating-point registers and configuration/status registers. */
- LDP W9, W10, [ SP ], # 0x10
- MSR FPSR, X9
- MSR FPCR, X10
- LDP Q30, Q31, [ SP ], # 0x20
- LDP Q28, Q29, [ SP ], # 0x20
- LDP Q26, Q27, [ SP ], # 0x20
- LDP Q24, Q25, [ SP ], # 0x20
- LDP Q22, Q23, [ SP ], # 0x20
- LDP Q20, Q21, [ SP ], # 0x20
- LDP Q18, Q19, [ SP ], # 0x20
- LDP Q16, Q17, [ SP ], # 0x20
- LDP Q14, Q15, [ SP ], # 0x20
- LDP Q12, Q13, [ SP ], # 0x20
- LDP Q10, Q11, [ SP ], # 0x20
- LDP Q8, Q9, [ SP ], # 0x20
- LDP Q6, Q7, [ SP ], # 0x20
- LDP Q4, Q5, [ SP ], # 0x20
- LDP Q2, Q3, [ SP ], # 0x20
- LDP Q0, Q1, [ SP ], # 0x20
- .endm
- /*-----------------------------------------------------------*/
- .macro portSAVE_CONTEXT
- #if ( configENABLE_MPU == 1 )
- /* Switch to use the EL1 stack pointer. */
- MSR SPSEL, # 1
- /* Store X0-X4 as they are being used to save the user allocated task stack and to program the MPU */
- STP X0, X1, [ SP, # - 0x10 ] !
- STP X2, X3, [ SP, # - 0x10 ] !
- STR X4, [ SP, # - 0x10 ] !
- /* Switch to use the EL0 stack pointer. */
- MSR SPSEL, # 0
- /* Store user allocated task stack and use ullContext as the SP */
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X2, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X2, X2, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X2, X2, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X0, X0, X2 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X1, [ X0 ]
- ADD X1, X1, #8 /* X1 = X1 + 8, X1 now points to ullTaskUnprivilegedSP in TCB. */
- MOV X0, SP
- STR X0, [ X1 ] /* Save ullTaskUnprivilegedSP on task's TCB */
- SUB X1, X1, #8 /* X1 = X1 - 8, X1 now points to pxTopOfStack in TCB. */
- LDR X1, [ X1 ]
- MOV SP, X1 /* Use pxTopOfStack ( ullContext ) as the SP. */
- savefuncontextgpregs
- #if ( configNUMBER_OF_CORES > 1 )
- MRS X1, ELR_EL1 /* Save ELR_EL1 before calling xPortIsTaskPrivileged which would change its value in case of multicore */
- STR X1, [ SP, # - 0x10 ] !
- #endif
- BL xPortIsTaskPrivileged
- #if ( configNUMBER_OF_CORES > 1 )
- LDR X1, [ SP ], # 0x10
- MSR ELR_EL1, X1
- #endif
- CBNZ X0, 3f /* If task is privileged, skip saving MPU context. */
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X2, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X2, X2, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X2, X2, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X0, X0, X2 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X0, [ X0 ]
- ADD X0, X0, #16 /* X0 = X0 + 16. X0 now points to MAIR_EL1 in TCB. */
- MRS X1, MAIR_EL1 /* X1 = MAIR_EL1. */
- STR X1, [ X0 ], # 0x8 /* Store MAIR_EL1 in TCB, X0 = X0 + 8. */
- portSTORE_MPU_REGIONS_ADDRESSES /* Store MPU region addresses onto TCB. */
- 3 :
- restorefuncontextgpregs
- MSR SPSEL, # 1
- /* Restore X0-X4. */
- LDR X4, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- #endif /* #if ( configENABLE_MPU == 1 ) */
- MSR SPSEL, # 0
- /* Save the entire context. */
- saveallgpregisters
- /* Save the SPSR and ELR values. */
- MRS X3, SPSR_EL1
- MRS X2, ELR_EL1
- STP X2, X3, [ SP, # - 0x10 ] !
- /* Save the critical section nesting depth. */
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, ullCriticalNesting
- add X0, X0, :lo12:ullCriticalNesting /* X0 = &ullCriticalNesting */
- #else
- adrp X0, ullCriticalNestings
- add X0, X0, :lo12:ullCriticalNestings /* X0 = &ullCriticalNestings */
- /* Calculate per-core index using MPIDR_EL1 for SMP support. */
- MRS X1, MPIDR_EL1 /* Read the Multiprocessor Affinity Register. */
- AND X1, X1, # 0xff /* Extract Aff0 (core ID). */
- LSL X1, X1, # 3 /* Multiply core ID by pointer size (8 bytes). */
- ADD X0, X0, X1 /* Add offset to base address. */
- #endif
- LDR X3, [ X0 ]
- /* Save the FPU context indicator. */
- adrp X0, ullPortTaskHasFPUContext
- add X0, X0, :lo12:ullPortTaskHasFPUContext /* X0 = &ullPortTaskHasFPUContext */
- #if ( configNUMBER_OF_CORES > 1 )
- ADD X0, X0, X1 /* Add to the base of the FPU array. */
- #endif
- LDR X2, [ X0 ]
- /* Save the FPU context, if any (32 128-bit registers). */
- CBZ X2, 4f /* FPU context not present, skip saving FPU registers. */
- savefloatregisters
- 4 :
- /* Store the critical nesting count and FPU context indicator. */
- STP X2, X3, [ SP, # - 0x10 ] !
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- MRS X1, MPIDR_EL1 /* Read Multiprocessor Affinity Register .*/
- AND X1, X1, # 0xff /* Extract core ID. */
- LSL X1, X1, # 3 /* Multiply core ID by pointer size. */
- ADD X0, X0, X1 /* Offset for current core's TCB pointer. */
- #endif
- LDR X1, [ X0 ]
- MOV X0, SP
- STR X0, [ X1 ] /* Save pxTopOfStack on the TCB. */
- /* Switch to use the EL1 stack pointer. */
- MSR SPSEL, # 1
- .endm
- /*-----------------------------------------------------------*/
- .macro portRESTORE_CONTEXT
- #if ( configENABLE_MPU == 1 )
- /* Switch to use the EL1 stack pointer. */
- MSR SPSEL, # 1
- savefuncontextgpregs
- BL xPortIsTaskPrivileged
- CBNZ X0, 3f /* If task is privileged, skip restoring MPU context. */
- /* Switch to use the EL0 stack pointer. */
- MSR SPSEL, # 0
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X2, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X2, X2, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X2, X2, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X0, X0, X2 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X0, [ X0 ]
- DMB SY /* Complete outstanding transfers before disabling MPU. */
- MRS X1, SCTLR_EL1 /* X1 = SCTLR_EL1 */
- BIC X1, X1, # (1 << 0) /* Clears bit 0 of X1 */
- MSR SCTLR_EL1, X1 /* Disable MPU. */
- ADD X0, X0, #16 /* X0 = X0 + 16. X0 now points to MAIR_EL1 in TCB. */
- LDR X1, [ X0 ], # 0x8 /* X1 = *X0 i.e. X1 = MAIR_EL1, X0 = X0 + 8. */
- MSR MAIR_EL1, X1 /* Program MAIR_EL1. */
- portLOAD_MPU_REGIONS_ADDRESSES /* Load MPU region addresses from TCB. */
- MRS X1, SCTLR_EL1 /* X1 = SCTLR_EL1 */
- ORR X1, X1, # (1 << 0) /* Sets bit 0 of X1 */
- MSR SCTLR_EL1, X1 /* Enable MPU. */
- DSB SY /* Force memory writes before continuing. */
- 3 :
- MSR SPSEL, # 1
- restorefuncontextgpregs
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /* Switch to use the EL0 stack pointer. */
- MSR SPSEL, # 0
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X2, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X2, X2, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X2, X2, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X0, X0, X2 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X1, [ X0 ]
- LDR X0, [ X1 ] /* X0 = Location of saved context in TCB. */
- MOV SP, X0
- LDP X2, X3, [ SP ], # 0x10 /* Retrieve critical nesting and FPU indicator */
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, ullCriticalNesting
- add X0, X0, :lo12:ullCriticalNesting /* X0 = &ullCriticalNesting */
- #else
- adrp X0, ullCriticalNestings
- add X0, X0, :lo12:ullCriticalNestings /* X0 = &ullCriticalNestings */
- /* Calculate offset for current core's ullCriticalNesting */
- MRS X1, MPIDR_EL1 /* Read Multiprocessor Affinity Register */
- AND X1, X1, # 0xff /* Extract Aff0, which contains the core ID */
- LSL X1, X1, # 3 /* Scale core ID to the size of a pointer (assuming 64-bit system) */
- ADD X0, X0, X1 /* Add offset for the current core's ullCriticalNesting */
- #endif
- MOV X1, # 255 /* Default mask */
- CBZ X3, 4f
- MOV X1, # portMAX_API_PRIORITY_MASK
- 4:
- MSR ICC_PMR_EL1, X1 /* Set interrupt mask */
- DSB SY
- ISB SY
- STR X3, [ X0 ] /* Restore critical nesting */
- /* Restore the FPU context indicator. */
- adrp X0, ullPortTaskHasFPUContext
- add X0, X0, :lo12:ullPortTaskHasFPUContext /* X0 = &ullPortTaskHasFPUContext */
- #if ( configNUMBER_OF_CORES > 1 )
- MRS X1, MPIDR_EL1 /* Read Multiprocessor Affinity Register */
- AND X1, X1, # 0xff /* Extract Aff0, which contains the core ID */
- LSL X1, X1, # 3 /* Scale core ID to the size of a pointer (assuming 64-bit system) */
- ADD X0, X0, X1 /* Add to the base of the FPU array */
- #endif
- STR X2, [ X0 ]
- /* Restore the FPU context, if any. */
- CBZ X2, 5f
- restorefloatregisters
- 5:
- LDP X2, X3, [ SP ], # 0x10 /* Restore SPSR and ELR */
- MSR SPSR_EL1, X3
- MSR ELR_EL1, X2
- restoreallgpregisters
- #if ( configENABLE_MPU == 1 )
- /* Save pxTopOfStack ( ullContext ) on the task's TCB and set SP_EL0 to ullTaskUnprivilegedSP. */
- MSR SPSEL, # 1
- STP X8, X9, [ SP, # - 0x10 ] !
- STR X10, [ SP, # - 0x10 ] !
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X8, pxCurrentTCB
- add X8, X8, :lo12:pxCurrentTCB /* X8 = &pxCurrentTCB */
- #else
- adrp X8, pxCurrentTCBs
- add X8, X8, :lo12:pxCurrentTCBs /* X8 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X10, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X10, X10, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X10, X10, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X8, X8, X10 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X9, [ X8 ]
- MRS X8, SP_EL0
- STR X8, [ X9 ] /* Store pxTopOfStack on task's TCB */
- ADD X9, X9, #8 /* X9 = X9 + 8. X1 now points to ullTaskUnprivilegedSP in TCB. */
- LDR X9, [ X9 ]
- MSR SP_EL0, X9 /* Use ullTaskUnprivilegedSP as SP_EL0. */
- LDR X10, [ SP ], # 0x10
- LDP X8, X9, [ SP ], # 0x10
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /* Switch to use the EL1 stack pointer. */
- MSR SPSEL, # 1
- .endm
- /*-----------------------------------------------------------*/
- /******************************************************************************
- * FreeRTOS_SWI_Handler handler is used to perform a context switch.
- *****************************************************************************/
- .align 8
- .type FreeRTOS_SWI_Handler, % function
- FreeRTOS_SWI_Handler:
- /* Save X0-X5 temporarily as they are used in the handler. */
- STP X0, X1, [SP, #-0x10]!
- STP X2, X3, [SP, #-0x10]!
- STP X4, X5, [SP, #-0x10]!
- MRS X4, ELR_EL1 /* Save exception return address. */
- MRS X5, SPSR_EL1 /* Save program status register address. */
- /* Decide action based on SVC immediate without corrupting any task context. */
- MRS X0, ESR_EL1
- /* Extract exception class. */
- LSR X1, X0, # 26
- CMP X1, # 0x15 /* 0x15 = SVC instruction. */
- B.NE FreeRTOS_Abort
- /* Extract SVC immediate from ISS[15:0]. */
- AND X2, X0, # 0xFFFF
- /* portSVC_YIELD: yield from a running task. */
- CMP X2, # portSVC_YIELD
- B.EQ FreeRTOS_Yield
- /* portSVC_START_FIRST_TASK: start first task on this core without saving any prior context. */
- CMP X2, # portSVC_START_FIRST_TASK
- B.EQ Start_First_Task
- 1:
- /* portSVC_DISABLE_INTERRUPTS: disable IRQs (DAIF.I) in SPSR_EL1 without touching task context. */
- CMP X2, # portSVC_DISABLE_INTERRUPTS
- B.NE 2f
- ORR X5, X5, # (1 << portPSTATE_I_BIT) /* Set I bit in SPSR_EL1 */
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- DSB SY
- ISB SY
- ERET
- 2:
- /* portSVC_ENABLE_INTERRUPTS: enable IRQs (DAIF.I clear) in SPSR_EL1 without touching task context. */
- CMP X2, # portSVC_ENABLE_INTERRUPTS
- B.NE 3f
- BIC X5, X5, # (1 << portPSTATE_I_BIT) /* Clear I bit in SPSR_EL1 */
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- ERET
- 3:
- /* portSVC_GET_CORE_ID: return core ID in X0 (Aff0 of MPIDR_EL1). */
- CMP X2, # portSVC_GET_CORE_ID
- B.NE 4f
- MRS X0, MPIDR_EL1
- AND X0, X0, # 0xff
- MSR SPSR_EL1, X5
- /* Restore X5-X1 while discarding old X0. */
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP XZR, X1, [ SP ], # 0x10
- ERET
- 4:
- /* portSVC_MASK_ALL_INTERRUPTS: set ICC_PMR_EL1 to max API mask and return previous-mask-equal flag in X0. */
- CMP X2, # portSVC_MASK_ALL_INTERRUPTS
- B.NE 5f
- /* Read current PMR and compare. */
- MRS X0, ICC_PMR_EL1
- CMP X0, # portMAX_API_PRIORITY_MASK
- B.EQ 41f
- /* Disable IRQs while updating PMR. */
- MSR DAIFSET, # 2
- DSB SY
- ISB SY
- /* Write new PMR value. */
- MOV X1, # portMAX_API_PRIORITY_MASK
- MSR ICC_PMR_EL1, X1
- DSB SY
- ISB SY
- /* Re-enable IRQs. */
- MSR DAIFCLR, # 2
- DSB SY
- ISB SY
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- 41:
- /* Restore X5-X1 while discarding old X0. */
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP XZR, X1, [ SP ], # 0x10
- ERET
- 5:
- /* portSVC_UNMASK_ALL_INTERRUPTS: set ICC_PMR_EL1 to portUNMASK_VALUE to unmask all interrupts. */
- CMP X2, # portSVC_UNMASK_ALL_INTERRUPTS
- B.NE 6f
- /* Disable IRQs while updating PMR. */
- MSR DAIFSET, # 2
- DSB SY
- ISB SY
- MOV X0, #portUNMASK_VALUE /* Unmask all interrupts. */
- MSR ICC_PMR_EL1, X0
- DSB SY
- ISB SY
- /* Re-enable IRQs. */
- MSR DAIFCLR, # 2
- DSB SY
- ISB SY
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- ERET
- 6:
- /* portSVC_UNMASK_INTERRUPTS: set ICC_PMR_EL1 to uxNewMaskValue stored in X0. */
- CMP X2, # portSVC_UNMASK_INTERRUPTS
- B.NE 7f
- /* Disable IRQs while updating PMR. */
- MSR DAIFSET, # 2
- DSB SY
- ISB SY
- LDR X0, [ SP, # 0x20 ] /* Original X0 */
- MSR ICC_PMR_EL1, X0
- DSB SY
- ISB SY
- /* Re-enable IRQs. */
- MSR DAIFCLR, # 2
- DSB SY
- ISB SY
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- ERET
- 7:
- #if ( configENABLE_MPU == 1 )
- /* portSVC_CHECK_PRIVILEGE: Check if the task is a privileged task */
- CMP X2, # portSVC_CHECK_PRIVILEGE
- B.NE 8f
- savefuncontextgpregs
- BL xPortIsTaskPrivileged
- restorefuncontextgpregexceptx0 /* xPortIsTaskPrivileged() return value is stored in X0. */
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- /* Restore X5-X1 while discarding old X0. */
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP XZR, X1, [ SP ], # 0x10
- ERET
- #endif /* #if ( configENABLE_MPU == 1 ) */
- 8:
- /* portSVC_SAVE_TASK_CONTEXT: Save task's context */
- CMP X2, # portSVC_SAVE_TASK_CONTEXT
- B.NE 9f
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- /* Restore X5-X0. */
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- portSAVE_CONTEXT
- ERET
- 9:
- /* portSVC_RESTORE_CONTEXT: Restore task's context */
- CMP X2, # portSVC_RESTORE_CONTEXT
- B.NE 10f
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- /* Restore X5-X0. */
- LDP X4, X5, [ SP ], # 0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- portRESTORE_CONTEXT
- ERET
- 10:
- /* portSVC_DELETE_CURRENT_TASK: Delete current task */
- CMP X2, # portSVC_DELETE_CURRENT_TASK
- B.NE 11f
- /* Restore X5-X0. */
- LDP X4, X5, [ SP ], #0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X1, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X1, X1, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X1, X1, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X0, X0, X1 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X0, [ X0 ] /* X0 = pxCurrentTCB */
- B vTaskDelete
- 11:
- /* portSVC_INTERRUPT_CORE: Interrupt core */
- CMP X2, # portSVC_INTERRUPT_CORE
- B.NE 12f
- LDR X0, [ SP, # 0x20 ] /* Original X0 */
- MSR ICC_SGI1R_EL1, X0 /* X0 contains the value to write to ICC_SGI1R_EL1 */
- MSR ELR_EL1, X4
- MSR SPSR_EL1, X5
- /* Restore X5-X0. */
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [ SP ], # 0x10
- LDP X0, X1, [ SP ], # 0x10
- ERET
- 12:
- #if ( configENABLE_MPU == 1 )
- /* ---------- SystemCallEnter? ---------------------------------*/
- LDR X3, =NUM_SYSTEM_CALLS
- CMP X2, X3
- BLO 121f /* imm 0 … NUM_SYSCALLS-1 */
- /* ---------- SystemCallExit? ----------------------------------*/
- LDR X3, =portSVC_SYSTEM_CALL_EXIT
- CMP X2, X3
- BEQ 122f
- /* ---------- SystemCallEnter -------------------------------------*/
- 121:
- /* If calling task is privileged, directly tail-call the implementation at EL1. */
- savefuncontextgpregs
- BL xPortIsTaskPrivileged
- restorefuncontextgpregexceptx0 /* X0 holds pdTRUE if privileged */
- CBNZ X0, priv_path
- /* Unprivileged tasks path */
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X0, pxCurrentTCB
- add X0, X0, :lo12:pxCurrentTCB /* X0 = &pxCurrentTCB */
- #else
- adrp X0, pxCurrentTCBs
- add X0, X0, :lo12:pxCurrentTCBs /* X0 = &pxCurrentTCBs */
- /* Get the core ID to index the TCB correctly. */
- MRS X1, MPIDR_EL1 /* Read the Multiprocessor Affinity Register */
- AND X1, X1, # 0xff /* Extract Aff0 which contains the core ID */
- LSL X1, X1, # 3 /* Scale the core ID to the size of a pointer (64-bit system) */
- ADD X0, X0, X1 /* Add the offset for the current core's TCB pointer */
- #endif
- LDR X0, [ X0 ]
- LDR X0, [ X0 ] /* X0 = Location of saved context in TCB. */
- /* Save inputs (X0-X3) and LR (X30)
- * onto the current task's context to be used by the system call implementation.
- */
- STR X30, [ X0, # ( portOFFSET_TO_LR * 8 ) ]
- /* Read original X0, X1, X2, and X3 from the EL1 stack without modifying SP, and store.
- * [SP+0x20] -> X0, [SP+0x28] -> X1, [SP+0x10] -> X2, [SP+0x18] -> X3. */
- LDR X1, [ SP, # 0x20 ] /* Original X0 */
- STR X1, [ X0, # ( portOFFSET_TO_X0 * 8 ) ]
- LDR X1, [ SP, # 0x28 ] /* Original X1 */
- STR X1, [ X0, # ( portOFFSET_TO_X1 * 8 ) ]
- LDR X1, [ SP, # 0x10 ] /* Original X2 */
- STR X1, [ X0, # ( portOFFSET_TO_X2 * 8 ) ]
- LDR X1, [ SP, # 0x18 ] /* Original X3 */
- STR X1, [ X0, # ( portOFFSET_TO_X3 * 8 ) ]
- /* Restore X2-X5 to their original values, discard X1 and X0 as they contain system call number
- * and location of task's saved context in TCB.
- */
- MOV X1, X2 /* Pass system call */
- LDP X4, X5, [ SP ], #0x10
- LDP X2, X3, [ SP ], #0x10
- ADD SP, SP, #0x10 /* Discard X0 and X1 */
- savesyscallcontextgpregs
- BL vSystemCallEnter /* returns after programming ELR/SPSR/SP_EL0 and args */
- /* Set LR for the syscall implementation to point to vRequestSystemCallExit. */
- adrp X30, vRequestSystemCallExit
- add X30, X30, :lo12:vRequestSystemCallExit
- restoresyscallcontextgpregs
- ERET
- priv_path:
- /* Load implementation address: uxSystemCallImplementations[X2] (64-bit entries). */
- adrp X3, uxSystemCallImplementations
- add X3, X3, :lo12:uxSystemCallImplementations
- LSL X2, X2, #3 /* Multiply index by size of pointer (8 bytes). */
- ADD X3, X3, X2 /* X3 = &uxSystemCallImplementations[X2] */
- LDR X3, [ X3 ] /* X3 = uxSystemCallImplementations[X2] */
- /* Return from exception directly to implementation; preserve original LR and registers. */
- MSR ELR_EL1, X3
- MSR SPSR_EL1, X5
- /* Restore X5-X0. */
- LDP X4, X5, [ SP ], #0x10
- LDP X2, X3, [ SP ], #0x10
- LDP X0, X1, [ SP ], #0x10
- ERET
- /* ---------- SystemCallExit -----------------------------------*/
- 122:
- LDR X0, [ SP, # 0x20 ] /* Restore X0 without changing SP as it contains system call return value */
- savefuncontextgpregs
- BL vSystemCallExit
- restorefuncontextgpregexceptx0
- /* Restore X5-X1 while discarding old X0. */
- LDP X4, X5, [ SP ], #0x10
- LDP X2, X3, [ SP ], #0x10
- LDP XZR, X1, [ SP ], #0x10
- ERET
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /* ---------- Unexpected EC – just hang in place ---------------------------*/
- FreeRTOS_Abort:
- B FreeRTOS_Abort
- FreeRTOS_Yield:
- MSR SPSR_EL1, X5
- /* Check if the task is in a critical section by inspecting ullCriticalNesting. */
- #if ( configNUMBER_OF_CORES > 1 )
- adrp X0, ullCriticalNestings
- add X0, X0, :lo12:ullCriticalNestings /* X0 = &ullCriticalNestings */
- MRS X1, MPIDR_EL1 /* Read the Multiprocessor Affinity Register. */
- AND X1, X1, # 0xff /* Extract Aff0 (core ID). */
- LSL X1, X1, # 3 /* Multiply core ID by pointer size (8 bytes). */
- ADD X0, X0, X1 /* Add offset to base address. */
- LDR X1, [ X0 ] /* Load ullCriticalNesting for this core. */
- CBNZ X1, Skip_Context_Switch /* Skip context switch if in a critical section. */
- #endif
- /* Restore X5-X0 to their original values before saving full context. */
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- portSAVE_CONTEXT
- savefuncontextgpregs
- #if ( configNUMBER_OF_CORES > 1 )
- MRS x0, mpidr_el1
- AND x0, x0, 255
- #endif
- BL vTaskSwitchContext
- restorefuncontextgpregs
- portRESTORE_CONTEXT
- ERET
- Skip_Context_Switch:
- /* Restore X5-X0 to their original values. */
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- ERET
- Start_First_Task:
- /* Restore X5-X0 to their original values. */
- LDP X4, X5, [SP], #0x10
- LDP X2, X3, [SP], #0x10
- LDP X0, X1, [SP], #0x10
- portRESTORE_CONTEXT
- ERET
- /******************************************************************************
- * vPortSaveTaskContext is used to save the task's context into its stack.
- *****************************************************************************/
- .align 8
- .type vPortSaveTaskContext, % function
- vPortSaveTaskContext:
- portSAVE_CONTEXT
- RET
- /******************************************************************************
- * vPortRestoreTaskContext is used to start the scheduler.
- *****************************************************************************/
- .align 8
- .type vPortRestoreTaskContext, % function
- vPortRestoreTaskContext:
- .set freertos_vector_base, _freertos_vector_table
- /* Install the FreeRTOS interrupt handlers. */
- LDR X1, = freertos_vector_base
- MSR VBAR_EL1, X1
- DSB SY
- ISB SY
- /* Start the first task. */
- portRESTORE_CONTEXT
- ERET
- /******************************************************************************
- * FreeRTOS_IRQ_Handler handles IRQ entry and exit.
- *
- * This handler is supposed to be used only for IRQs and never for FIQs. Per ARM
- * GIC documentation [1], Group 0 interrupts are always signaled as FIQs. Since
- * this handler is only for IRQs, We can safely assume Group 1 while accessing
- * Interrupt Acknowledge and End Of Interrupt registers and therefore, use
- * ICC_IAR1_EL1 and ICC_EOIR1_EL1.
- *
- * [1] https://developer.arm.com/documentation/198123/0300/Arm-CoreLink-GIC-fundamentals
- *****************************************************************************/
- .align 8
- .type FreeRTOS_IRQ_Handler, % function
- FreeRTOS_IRQ_Handler:
- /* Save volatile registers. */
- saveallgpregisters
- savefloatregisters
- /* Save the SPSR and ELR. */
- MRS X3, SPSR_EL1
- MRS X2, ELR_EL1
- STP X2, X3, [ SP, # - 0x10 ] !
- /* Increment the interrupt nesting counter. */
- #if ( configNUMBER_OF_CORES == 1 )
- adrp X5, ullPortInterruptNesting
- add X5, X5, :lo12:ullPortInterruptNesting /* X5 = &ullPortInterruptNesting */
- #else
- adrp X5, ullPortInterruptNestings
- add X5, X5, :lo12:ullPortInterruptNestings /* X5 = &ullPortInterruptNestings */
- MRS X2, MPIDR_EL1 /* Read Multiprocessor Affinity Register. */
- AND X2, X2, # 0xff /* Extract Aff0, which contains the core ID. */
- LSL X2, X2, # 3 /* Scale core ID to the size of a pointer (assuming 64-bit system). */
- /* Calculate offset for the current core's ullPortYieldRequired and load its address. */
- ADD X5, X5, X2 /* Add offset for the current core's ullPortYieldRequired. */
- #endif
- LDR X1, [ X5 ] /* Old nesting count in X1. */
- ADD X6, X1, # 1
- STR X6, [ X5 ] /* Address of nesting count variable in X5. */
- /* Maintain the interrupt nesting information across the function call. */
- STP X1, X5, [ SP, # - 0x10 ] !
- /* Read interrupt ID from the interrupt acknowledge register and store it
- * in X0 for future parameter and interrupt clearing use. */
- MRS X0, ICC_IAR1_EL1
- /* Maintain the interrupt ID value across the function call. */
- STP X0, X1, [ SP, # - 0x10 ] !
- savefuncontextgpregs
- /* Call the C handler. */
- BL vApplicationIRQHandler
- restorefuncontextgpregs
- /* Disable interrupts. */
- MSR DAIFSET, # 2
- DSB SY
- ISB SY
- /* Restore the interrupt ID value. */
- LDP X0, X1, [ SP ], # 0x10
- /* End IRQ processing by writing interrupt ID value to the EOI register. */
- MSR ICC_EOIR1_EL1, X0
- /* Restore the critical nesting count. */
- LDP X1, X5, [ SP ], # 0x10
- STR X1, [ X5 ]
- /* Has interrupt nesting unwound? */
- CMP X1, # 0
- B.NE Exit_IRQ_No_Context_Switch
- /* Is a context switch required? */
- adrp X0, ullPortYieldRequired
- add X0, X0, :lo12:ullPortYieldRequired /* X0 = &ullPortYieldRequired */
- #if ( configNUMBER_OF_CORES > 1 )
- MRS X2, MPIDR_EL1 /* Read Multiprocessor Affinity Register. */
- AND X2, X2, # 0xff /* Extract Aff0, which contains the core ID. */
- LSL X2, X2, # 3 /* Scale core ID to the size of a pointer (assuming 64-bit system). */
- /* Calculate offset for the current core's ullPortYieldRequired and load its address. */
- ADD X0, X0, X2 /* Add offset for the current core's ullPortYieldRequired. */
- #endif
- LDR X1, [ X0 ]
- CMP X1, # 0
- B.EQ Exit_IRQ_No_Context_Switch
- /* Check if the task is in a critical section by inspecting ullCriticalNesting. */
- #if ( configNUMBER_OF_CORES > 1 )
- adrp X0, ullCriticalNestings
- add X0, X0, :lo12:ullCriticalNestings /* X0 = &ullCriticalNestings */
- MRS X1, MPIDR_EL1 /* Read the Multiprocessor Affinity Register. */
- AND X1, X1, # 0xff /* Extract Aff0 (core ID). */
- LSL X1, X1, # 3 /* Multiply core ID by pointer size (8 bytes). */
- ADD X0, X0, X1 /* Add offset to base address. */
- LDR X1, [ X0 ] /* Load ullCriticalNesting for this core. */
- CBNZ X1, Exit_IRQ_No_Context_Switch /* Skip context switch if in a critical section. */
- #endif
- /* Reset ullPortYieldRequired to 0. */
- MOV X2, # 0
- STR X2, [ X0 ]
- /* Restore volatile registers. */
- LDP X4, X5, [ SP ], # 0x10 /* SPSR and ELR. */
- MSR SPSR_EL1, X5
- MSR ELR_EL1, X4
- DSB SY
- ISB SY
- restorefloatregisters
- restoreallgpregisters
- /* Save the context of the current task and select a new task to run. */
- portSAVE_CONTEXT
- #if configNUMBER_OF_CORES > 1
- MRS x0, mpidr_el1
- AND x0, x0, 255
- #endif
- savefuncontextgpregs
- BL vTaskSwitchContext
- restorefuncontextgpregs
- portRESTORE_CONTEXT
- ERET
- Exit_IRQ_No_Context_Switch:
- /* Restore volatile registers. */
- LDP X4, X5, [ SP ], # 0x10 /* SPSR and ELR. */
- MSR SPSR_EL1, X5
- MSR ELR_EL1, X4
- DSB SY
- ISB SY
- restorefloatregisters
- restoreallgpregisters
- ERET
- /******************************************************************************
- * If the application provides an implementation of vApplicationIRQHandler(),
- * then it will get called directly without saving the FPU registers on
- * interrupt entry, and this weak implementation of
- * vApplicationIRQHandler() will not get called.
- *
- * If the application provides its own implementation of
- * vApplicationFPUSafeIRQHandler() then this implementation of
- * vApplicationIRQHandler() will be called, save the FPU registers, and then
- * call vApplicationFPUSafeIRQHandler().
- *
- * Therefore, if the application writer wants FPU registers to be saved on
- * interrupt entry their IRQ handler must be called
- * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
- * FPU registers to be saved on interrupt entry their IRQ handler must be
- * called vApplicationIRQHandler().
- *****************************************************************************/
- .align 8
- .weak vApplicationIRQHandler
- .type vApplicationIRQHandler, % function
- vApplicationIRQHandler:
- /* Save FPU registers (32 128-bits + 2 64-bits configuration and status registers). */
- savefloatregisters
- savefuncontextgpregs
- /* Call the C handler. */
- BL vApplicationFPUSafeIRQHandler
- restorefuncontextgpregs
- /* Restore FPU registers. */
- restorefloatregisters
- RET
- .end
|