| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786 |
- /*
- * 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
- *
- */
- /* Standard includes. */
- #include <stdlib.h>
- #include <string.h>
- /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
- * all the API functions to use the MPU wrappers. That should only be done when
- * task.h is included from an application file. */
- #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
- /* Scheduler includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- /* MPU includes. */
- #include "mpu_wrappers.h"
- #include "mpu_syscall_numbers.h"
- #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
- #ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS
- #error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. Refer to Cortex-A equivalent: /* https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors */
- #endif
- #ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET
- #error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. Refer to Cortex-A equivalent: /* https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors */
- #endif
- #ifndef configUNIQUE_INTERRUPT_PRIORITIES
- #error configUNIQUE_INTERRUPT_PRIORITIES must be defined. Refer to Cortex-A equivalent: /* https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors */
- #endif
- #ifndef configSETUP_TICK_INTERRUPT
- #error configSETUP_TICK_INTERRUPT() must be defined. Refer to Cortex-A equivalent: /* https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors */
- #endif /* configSETUP_TICK_INTERRUPT */
- #ifndef configMAX_API_CALL_INTERRUPT_PRIORITY
- #error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. Refer to Cortex-A equivalent: /* https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors */
- #endif
- #if configMAX_API_CALL_INTERRUPT_PRIORITY == 0
- #error "configMAX_API_CALL_INTERRUPT_PRIORITY must not be set to 0"
- #endif
- #if configMAX_API_CALL_INTERRUPT_PRIORITY > configUNIQUE_INTERRUPT_PRIORITIES
- #error "configMAX_API_CALL_INTERRUPT_PRIORITY must be less than or equal to configUNIQUE_INTERRUPT_PRIORITIES as the lower the numeric priority value the higher the logical interrupt priority"
- #endif
- #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
- /* Check the configuration. */
- #if ( configMAX_PRIORITIES > 32 )
- #error "configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 different priorities as tasks that share a priority will time slice."
- #endif
- #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
- /* In case security extensions are implemented. */
- #if configMAX_API_CALL_INTERRUPT_PRIORITY <= ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
- #error "configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )"
- #endif
- #ifndef configCLEAR_TICK_INTERRUPT
- #error configCLEAR_TICK_INTERRUPT must be defined in FreeRTOSConfig.h to clear which ever interrupt was used to generate the tick interrupt.
- #endif
- #if configNUMBER_OF_CORES < 1
- #error configNUMBER_OF_CORES must be set to 1 or greater. If the application is not using multiple cores then set configNUMBER_OF_CORES to 1.
- #endif /* configNUMBER_OF_CORES < 1 */
- #ifndef configENABLE_MPU
- #error configENABLE_MPU must be defined in FreeRTOSConfig.h. Set configENABLE_MPU to 1 to enable the MPU or 0 to disable the MPU.
- #endif /* #if ( configENABLE_MPU == 1 ) */
- #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 != 0) )
- #error Arm Cortex-R82 port supports only MPU Wrapper V2.
- #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 != 0) */
- /* A critical section is exited when the critical section nesting count reaches
- * this value. */
- #define portNO_CRITICAL_NESTING ( ( size_t ) 0 )
- /* Macro to unmask all interrupt priorities. */
- #define portCLEAR_INTERRUPT_PRIORITIES_MASK() __asm volatile ( "SVC %0" : : "i" ( portSVC_UNMASK_ALL_INTERRUPTS ) : "memory" )
- /* Macro to unmask all interrupt priorities from EL1. */
- #define portCLEAR_INTERRUPT_PRIORITIES_MASK_FROM_EL1() \
- { \
- __asm volatile ( \
- " MSR DAIFSET, # 2 \n" \
- " DSB SY \n" \
- " ISB SY \n" \
- " MOV X0, %0 \n" \
- " MSR ICC_PMR_EL1, X0 \n" \
- " DSB SY \n" \
- " ISB SY \n" \
- " MSR DAIFCLR, # 2 \n" \
- " DSB SY \n" \
- " ISB SY \n" \
- : \
- : "i" ( portUNMASK_VALUE ) \
- ); \
- }
- /* Tasks are not created with a floating point context, but can be given a
- * floating point context after they have been created. A variable is stored as
- * part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
- * does not have an FPU context, or any other value if the task does have an FPU
- * context. */
- #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
- /* Constants required to setup the initial task context. */
- #define portSP_ELx ( ( StackType_t ) 0x01 )
- #define portSP_EL0 ( ( StackType_t ) 0x00 )
- #define portEL1 ( ( StackType_t ) 0x04 )
- #define portEL0 ( ( StackType_t ) 0x00 )
- #define portINITIAL_PSTATE_EL0 ( portEL0 | portSP_EL0 )
- #define portINITIAL_PSTATE_EL1 ( portEL1 | portSP_EL0 )
- /* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
- * point is zero. */
- #define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
- /* Masks all bits in the APSR other than the mode bits. */
- #define portAPSR_MODE_BITS_MASK ( 0x0C )
- /* The I bit in the DAIF bits. */
- #define portDAIF_I ( 0x80 )
- #define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
- #define portBIT_0_SET ( ( uint8_t ) 0x01 )
- /* The space on the stack required to hold the FPU registers.
- * There are 32 128-bit plus 2 64-bit status registers. */
- #define portFPU_REGISTER_WORDS ( ( 32 * 2 ) + 2 )
- /*-----------------------------------------------------------*/
- #if ( configENABLE_MPU == 1 )
- /**
- * @brief Setup the Memory Protection Unit (MPU).
- */
- PRIVILEGED_FUNCTION void vSetupMPU( void );
- /**
- * @brief Enable the Memory Protection Unit (MPU).
- */
- PRIVILEGED_FUNCTION void vEnableMPU( void );
- /**
- * @brief Called from an ISR and returns the core ID the code is executing on.
- *
- * @return uint8_t The core ID.
- */
- PRIVILEGED_FUNCTION uint8_t ucPortGetCoreIDFromIsr( void );
- /**
- * @brief Checks whether or not the calling task is privileged.
- *
- * @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
- */
- PRIVILEGED_FUNCTION BaseType_t xPortIsTaskPrivileged( void );
- /**
- * @brief Extract MPU region's access permissions from the Protection Region Base Address Register
- * (PRBAR_EL1) value.
- *
- * @param ullPrbarEl1Value PRBAR_EL1 value for the MPU region.
- *
- * @return uint32_t Access permissions.
- */
- PRIVILEGED_FUNCTION static uint32_t prvGetRegionAccessPermissions( uint64_t ullPrbarEl1Value );
- /**
- * @brief Does the necessary work to enter a system call.
- *
- * @param pullPrivilegedOnlyTaskStack The task's privileged SP when the SVC was raised.
- * @param ucSystemCallNumber The system call number of the system call.
- */
- PRIVILEGED_FUNCTION void vSystemCallEnter( uint64_t * pullPrivilegedOnlyTaskStack,
- uint8_t ucSystemCallNumber );
- /**
- * @brief Raise SVC for exiting from a system call.
- */
- PRIVILEGED_FUNCTION __attribute__( ( naked ) ) void vRequestSystemCallExit( void );
- /**
- * @brief Sets up the task stack so that upon returning from
- * SVC, the task stack is used again.
- *
- * @param ullSystemCallReturnValue The actual system call return value.
- */
- PRIVILEGED_FUNCTION void vSystemCallExit( uint64_t ullSystemCallReturnValue );
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /*
- * Starts the first task executing. This function is necessarily written in
- * assembly code so is implemented in portASM.s.
- */
- extern void vPortRestoreTaskContext( void );
- extern void vGIC_EnableIRQ( uint32_t ulInterruptID );
- extern void vGIC_SetPriority( uint32_t ulInterruptID, uint32_t ulPriority );
- extern void vGIC_PowerUpRedistributor( void );
- extern void vGIC_EnableCPUInterface( void );
- /*-----------------------------------------------------------*/
- #if ( configNUMBER_OF_CORES == 1 )
- PRIVILEGED_DATA volatile uint64_t ullCriticalNesting = 0ULL;
- /* Saved as part of the task context. If ullPortTaskHasFPUContext is non-zero
- * then floating point context must be saved and restored for the task. */
- PRIVILEGED_DATA uint64_t ullPortTaskHasFPUContext = pdFALSE;
- /* Set to 1 to pend a context switch from an ISR. */
- PRIVILEGED_DATA uint64_t ullPortYieldRequired = pdFALSE;
- /* Counts the interrupt nesting depth. A context switch is only performed if
- * if the nesting depth is 0. */
- PRIVILEGED_DATA uint64_t ullPortInterruptNesting = 0;
- #else /* #if ( configNUMBER_OF_CORES == 1 ) */
- PRIVILEGED_DATA volatile uint64_t ullCriticalNestings[ configNUMBER_OF_CORES ] = { 0 };
- /* Flags to check if the secondary cores are ready. */
- PRIVILEGED_DATA volatile uint8_t ucSecondaryCoresReadyFlags[ configNUMBER_OF_CORES - 1 ] = { 0 };
- /* Flag to signal that the primary core has done all the shared initialisations. */
- PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
- /* Saved as part of the task context. If ullPortTaskHasFPUContext is non-zero
- * then floating point context must be saved and restored for the task. */
- PRIVILEGED_DATA uint64_t ullPortTaskHasFPUContext[ configNUMBER_OF_CORES ] = { pdFALSE };
- /* Set to 1 to pend a context switch from an ISR. */
- PRIVILEGED_DATA uint64_t ullPortYieldRequired[ configNUMBER_OF_CORES ] = { pdFALSE };
- /* Counts the interrupt nesting depth. A context switch is only performed if
- * if the nesting depth is 0. */
- PRIVILEGED_DATA uint64_t ullPortInterruptNestings[ configNUMBER_OF_CORES ] = { 0 };
- #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- #if ( configENABLE_MPU == 1 )
- /* Set to pdTRUE when the scheduler is started. */
- PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE;
- #endif /* ( configENABLE_MPU == 1 ) */
- /*-----------------------------------------------------------*/
- #if ( configENABLE_MPU == 1 )
- StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
- TaskFunction_t pxCode,
- void * pvParameters,
- BaseType_t xRunPrivileged,
- xMPU_SETTINGS * xMPUSettings )
- {
- uint32_t ulIndex = 0;
- /* Layout must match portRESTORE_CONTEXT pop order (descending stack):
- * 1) FPU flag, 2) Critical nesting, 3) Optional FPU save area,
- * 4) ELR (PC), 5) SPSR (PSTATE), 6) GPRs in restore order pairs.
- */
- /* 1) FPU flag and 2) Critical nesting. */
- #if ( configUSE_TASK_FPU_SUPPORT == portTASK_NO_FPU_CONTEXT_BY_DEFAULT )
- xMPUSettings->ullContext[ ulIndex++ ] = portNO_FLOATING_POINT_CONTEXT; /* FPU flag */
- xMPUSettings->ullContext[ ulIndex++ ] = portNO_CRITICAL_NESTING; /* Critical nesting */
- #elif ( configUSE_TASK_FPU_SUPPORT == portTASK_HAVE_FPU_CONTEXT_BY_DEFAULT )
- xMPUSettings->ullContext[ ulIndex++ ] = pdTRUE; /* FPU flag */
- xMPUSettings->ullContext[ ulIndex++ ] = portNO_CRITICAL_NESTING; /* Critical nesting */
- #if ( configNUMBER_OF_CORES == 1 )
- ullPortTaskHasFPUContext = pdTRUE;
- #else
- ullPortTaskHasFPUContext[ portGET_CORE_ID() ] = pdTRUE;
- #endif
- #else
- #error "Invalid configUSE_TASK_FPU_SUPPORT setting - must be 1 or 2."
- #endif
- /* 3) Optional FPU save area immediately after the flag+critical pair. */
- #if ( configUSE_TASK_FPU_SUPPORT == portTASK_HAVE_FPU_CONTEXT_BY_DEFAULT )
- memset( &xMPUSettings->ullContext[ ulIndex ], 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );
- ulIndex += portFPU_REGISTER_WORDS;
- #endif
- /* 4) ELR (PC) and 5) SPSR (PSTATE). */
- xMPUSettings->ullContext[ ulIndex++ ] = ( StackType_t ) pxCode; /* ELR */
- if( xRunPrivileged == pdTRUE )
- {
- xMPUSettings->ullContext[ ulIndex++ ] = portINITIAL_PSTATE_EL1; /* SPSR */
- }
- else
- {
- xMPUSettings->ullContext[ ulIndex++ ] = portINITIAL_PSTATE_EL0; /* SPSR */
- }
- /* 6) General-purpose registers in the order expected by restoreallgpregisters. */
- xMPUSettings->ullContext[ ulIndex++ ] = ( StackType_t ) 0x00; /* X30 (LR) */
- xMPUSettings->ullContext[ ulIndex++ ] = ( StackType_t ) 0x00; /* XZR (dummy) */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2828282828282828ULL; /* X28 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2929292929292929ULL; /* X29 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2626262626262626ULL; /* X26 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2727272727272727ULL; /* X27 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2424242424242424ULL; /* X24 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2525252525252525ULL; /* X25 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2222222222222222ULL; /* X22 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2323232323232323ULL; /* X23 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2020202020202020ULL; /* X20 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x2121212121212121ULL; /* X21 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1818181818181818ULL; /* X18 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1919191919191919ULL; /* X19 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1616161616161616ULL; /* X16 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1717171717171717ULL; /* X17 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1414141414141414ULL; /* X14 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1515151515151515ULL; /* X15 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1212121212121212ULL; /* X12 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1313131313131313ULL; /* X13 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1010101010101010ULL; /* X10 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x1111111111111111ULL; /* X11 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0808080808080808ULL; /* X8 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0909090909090909ULL; /* X9 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0606060606060606ULL; /* X6 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0707070707070707ULL; /* X7 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0404040404040404ULL; /* X4 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0505050505050505ULL; /* X5 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0202020202020202ULL; /* X2 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0303030303030303ULL; /* X3 */
- xMPUSettings->ullContext[ ulIndex++ ] = ( StackType_t ) pvParameters; /* X0 */
- xMPUSettings->ullContext[ ulIndex++ ] = 0x0101010101010101ULL; /* X1 */
- if( xRunPrivileged == pdTRUE )
- {
- xMPUSettings->ullTaskFlags |= portTASK_IS_PRIVILEGED_FLAG;
- }
- else
- {
- xMPUSettings->ullTaskFlags &= ( ~portTASK_IS_PRIVILEGED_FLAG );
- }
- xMPUSettings->ullTaskUnprivilegedSP = ( ( uint64_t ) pxTopOfStack & portMPU_PRBAR_EL1_ADDRESS_MASK );
- return &( xMPUSettings->ullContext[ 0 ] );
- }
- #else /* #if ( configENABLE_MPU == 1 ) */
- /*
- * See header file for description.
- */
- StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
- TaskFunction_t pxCode,
- void * pvParameters )
- {
- /* Setup the initial stack of the task. The stack is set exactly as
- * expected by the portRESTORE_CONTEXT() macro. */
- /* First all the general purpose registers. */
- pxTopOfStack--;
- *pxTopOfStack = 0x0101010101010101ULL; /* R1 */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0303030303030303ULL; /* R3 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0202020202020202ULL; /* R2 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0505050505050505ULL; /* R5 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0404040404040404ULL; /* R4 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0707070707070707ULL; /* R7 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0606060606060606ULL; /* R6 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0909090909090909ULL; /* R9 */
- pxTopOfStack--;
- *pxTopOfStack = 0x0808080808080808ULL; /* R8 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1111111111111111ULL; /* R11 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1010101010101010ULL; /* R10 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1313131313131313ULL; /* R13 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1212121212121212ULL; /* R12 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1515151515151515ULL; /* R15 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1414141414141414ULL; /* R14 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1717171717171717ULL; /* R17 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1616161616161616ULL; /* R16 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1919191919191919ULL; /* R19 */
- pxTopOfStack--;
- *pxTopOfStack = 0x1818181818181818ULL; /* R18 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2121212121212121ULL; /* R21 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2020202020202020ULL; /* R20 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2323232323232323ULL; /* R23 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2222222222222222ULL; /* R22 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2525252525252525ULL; /* R25 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2424242424242424ULL; /* R24 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2727272727272727ULL; /* R27 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2626262626262626ULL; /* R26 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2929292929292929ULL; /* R29 */
- pxTopOfStack--;
- *pxTopOfStack = 0x2828282828282828ULL; /* R28 */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x00; /* XZR - has no effect, used so there are an even number of registers. */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) 0x00; /* R30 - procedure call link register. */
- pxTopOfStack--;
- *pxTopOfStack = portINITIAL_PSTATE_EL0;
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) pxCode; /* Exception return address. */
- #if ( configUSE_TASK_FPU_SUPPORT == portTASK_NO_FPU_CONTEXT_BY_DEFAULT )
- {
- /* The task will start with a critical nesting count of 0 as interrupts are
- * enabled. */
- pxTopOfStack--;
- *pxTopOfStack = portNO_CRITICAL_NESTING;
- /* The task will start without a floating point context. A task that
- * uses the floating point hardware must call vPortTaskUsesFPU() before
- * executing any floating point instructions. */
- pxTopOfStack--;
- *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
- }
- #elif ( configUSE_TASK_FPU_SUPPORT == portTASK_HAVE_FPU_CONTEXT_BY_DEFAULT )
- {
- /* The task will start with a floating point context. Leave enough
- * space for the registers - and ensure they are initialised to 0. */
- pxTopOfStack -= portFPU_REGISTER_WORDS;
- memset( pxTopOfStack, 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );
- /* The task will start with a critical nesting count of 0 as interrupts are
- * enabled. */
- pxTopOfStack--;
- *pxTopOfStack = portNO_CRITICAL_NESTING;
- pxTopOfStack--;
- *pxTopOfStack = pdTRUE;
- #if ( configNUMBER_OF_CORES == 1 )
- ullPortTaskHasFPUContext = pdTRUE;
- #else
- ullPortTaskHasFPUContext[ portGET_CORE_ID() ] = pdTRUE;
- #endif
- }
- #else /* if ( configUSE_TASK_FPU_SUPPORT == portTASK_NO_FPU_CONTEXT_BY_DEFAULT ) */
- {
- #error "Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 1, 2, or left undefined."
- }
- #endif /* if ( configUSE_TASK_FPU_SUPPORT == portTASK_NO_FPU_CONTEXT_BY_DEFAULT ) */
- return pxTopOfStack;
- }
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /*-----------------------------------------------------------*/
- #if ( configENABLE_MPU == 1 )
- /**
- * @brief Store a task's MPU settings in its TCB.
- *
- * @ingroup Task Context
- * @ingroup MPU Control
- *
- * @param xMPUSettings The MPU settings in TCB.
- * @param xRegions The MPU regions requested by the task.
- * @param pxBottomOfStack The base address of the task's Stack.
- * @param xStackDepth The length of the task's stack.
- */
- void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
- const struct xMEMORY_REGION * const xRegions,
- StackType_t * pxBottomOfStack,
- StackType_t xStackDepth ) /* PRIVILEGED_FUNCTION */
- {
- uint64_t ullRegionStartAddress, ullRegionEndAddress;
- uint8_t ucIndex = 0, ucRegionNumber;
- #if defined( __ARMCC_VERSION )
- /* Declaration when these variable are defined in code instead of being
- * exported from linker scripts. */
- extern uint64_t * __privileged_sram_start__;
- extern uint64_t * __privileged_sram_end__;
- #else
- /* Declaration when these variable are exported from linker scripts. */
- extern uint64_t __privileged_sram_start__[];
- extern uint64_t __privileged_sram_end__[];
- #endif /* defined( __ARMCC_VERSION ) */
- /* Setup MAIR_EL1. */
- xMPUSettings->ullMairEl1 = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_EL1_ATTR0_POS ) & portMPU_MAIR_EL1_ATTR0_MASK );
- xMPUSettings->ullMairEl1 |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_EL1_ATTR1_POS ) & portMPU_MAIR_EL1_ATTR1_MASK );
- /* This function is called automatically when the task is created - in
- * which case the stack region parameters will be valid. At all other
- * times the stack parameters will not be valid and it is assumed that
- * the stack region has already been configured. */
- if( xStackDepth > 0 )
- {
- ullRegionStartAddress = ( uint64_t ) pxBottomOfStack;
- ullRegionEndAddress = ( uint64_t ) pxBottomOfStack + ( xStackDepth * ( configSTACK_DEPTH_TYPE ) sizeof( StackType_t ) ) - 1;
- /* If the stack is within the privileged SRAM, do not protect it
- * using a separate MPU region. This is needed because this
- * region is already protected using an MPU region and ARMv8-R does
- * not allow overlapping MPU regions.
- */
- if( ( ullRegionStartAddress >= ( uint64_t ) __privileged_sram_start__ ) &&
- ( ullRegionEndAddress <= ( uint64_t ) __privileged_sram_end__ ) )
- {
- xMPUSettings->xRegionsSettings[ portSTACK_REGION_INDEX ].ullPrbarEl1 = 0;
- xMPUSettings->xRegionsSettings[ portSTACK_REGION_INDEX ].ullPrlarEl1 = 0;
- }
- else
- {
- /* Define the region that allows access to the stack. */
- ullRegionStartAddress &= portMPU_PRBAR_EL1_ADDRESS_MASK;
- ullRegionEndAddress &= portMPU_PRLAR_EL1_ADDRESS_MASK;
- xMPUSettings->xRegionsSettings[ portSTACK_REGION_INDEX ].ullPrbarEl1 = ( ullRegionStartAddress ) |
- ( portMPU_REGION_INNER_SHAREABLE ) |
- ( portMPU_REGION_READ_WRITE ) |
- ( portMPU_REGION_EXECUTE_NEVER );
- xMPUSettings->xRegionsSettings[ portSTACK_REGION_INDEX ].ullPrlarEl1 = ( ullRegionEndAddress ) |
- ( portMPU_PRLAR_EL1_ATTR_INDEX0 ) |
- ( portMPU_PRLAR_EL1_REGION_ENABLE );
- }
- }
- /* User supplied configurable regions. */
- for( ucRegionNumber = 1; ucRegionNumber <= portNUM_CONFIGURABLE_REGIONS; ucRegionNumber++ )
- {
- /* If xRegions is NULL i.e. the task has not specified any MPU
- * region, the else part ensures that all the configurable MPU
- * regions are invalidated.
- * The minimum region size is 64 Bytes.
- */
- if( xRegions != NULL )
- {
- /* Configure the region only if the base address is non-NULL.
- * The user may choose to use only a subset of the available MPU regions.
- * This check prevents undefined regions (i.e. regions with a NULL base
- * address) from being configured and from triggering the size-check
- * assertion below.
- */
- if ( xRegions[ ucIndex ].pvBaseAddress != NULL )
- {
- configASSERT( xRegions[ ucIndex ].ulLengthInBytes >= 64UL );
- uint64_t ullPrbarEl1RegValue, ullPrlarEl1RegValue;
- /* Translate the generic region definition contained in xRegions
- * into the ARMv8-R specific MPU settings that are then stored in
- * xMPUSettings.
- */
- ullRegionStartAddress = ( ( uint64_t ) xRegions[ ucIndex ].pvBaseAddress ) & portMPU_PRBAR_EL1_ADDRESS_MASK;
- ullRegionEndAddress = ( uint64_t ) xRegions[ ucIndex ].pvBaseAddress + xRegions[ ucIndex ].ulLengthInBytes - 1;
- ullRegionEndAddress &= portMPU_PRLAR_EL1_ADDRESS_MASK;
- /* Checks for overlaps with another user defined regions and stack region, which are already configured. */
- for( uint8_t ucUserRegionNumber = 0; ucUserRegionNumber < portNUM_CONFIGURABLE_REGIONS; ucUserRegionNumber++ )
- {
- /* Check for overlap. */
- if( ( portIS_ADDRESS_WITHIN_RANGE( ullRegionStartAddress,
- ( xMPUSettings->xRegionsSettings[ ucUserRegionNumber ].ullPrbarEl1 & portMPU_PRBAR_EL1_ADDRESS_MASK ),
- ( xMPUSettings->xRegionsSettings[ ucUserRegionNumber ].ullPrlarEl1 & portMPU_PRLAR_EL1_ADDRESS_MASK ) ) ||
- ( portIS_ADDRESS_WITHIN_RANGE( ullRegionEndAddress,
- ( xMPUSettings->xRegionsSettings[ ucUserRegionNumber ].ullPrbarEl1 & portMPU_PRBAR_EL1_ADDRESS_MASK ),
- ( xMPUSettings->xRegionsSettings[ ucUserRegionNumber ].ullPrlarEl1 & portMPU_PRLAR_EL1_ADDRESS_MASK ) ) ) ) )
- {
- /* Overlap detected - assert. */
- configASSERT( NULL );
- }
- }
- /* Checks for overlaps with kernel programmed regions which are already programmed as part of vSetupMPU. */
- for (uint8_t ucProgrammedRegionIndex = 0; ucProgrammedRegionIndex < 4; ucProgrammedRegionIndex++)
- {
- __asm volatile ( "msr PRSELR_EL1, %0" : : "r" ( ( uint64_t ) ucProgrammedRegionIndex ) );
- __asm volatile ( "mrs %0, PRBAR_EL1" : "=r" ( ullPrbarEl1RegValue ) );
- ullPrbarEl1RegValue &= portMPU_PRBAR_EL1_ADDRESS_MASK;
- __asm volatile ( "mrs %0, PRLAR_EL1" : "=r" ( ullPrlarEl1RegValue ) );
- ullPrlarEl1RegValue &= portMPU_PRLAR_EL1_ADDRESS_MASK;
- /* Check for overlap. */
- if( ( portIS_ADDRESS_WITHIN_RANGE( ullRegionStartAddress,
- ullPrbarEl1RegValue,
- ullPrlarEl1RegValue ) ) ||
- ( portIS_ADDRESS_WITHIN_RANGE( ullRegionEndAddress,
- ullPrbarEl1RegValue,
- ullPrlarEl1RegValue ) ) )
- {
- /* Overlap detected - assert. */
- configASSERT( NULL );
- }
- }
- /* Start address. */
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 = ( ullRegionStartAddress );
- /* RO/RW. */
- if( ( xRegions[ ucIndex ].ulParameters & tskMPU_REGION_READ_ONLY ) != 0 )
- {
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 |= ( portMPU_REGION_READ_ONLY );
- }
- else
- {
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 |= ( portMPU_REGION_READ_WRITE );
- }
- /* XN. */
- if( ( xRegions[ ucIndex ].ulParameters & tskMPU_REGION_EXECUTE_NEVER ) != 0 )
- {
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 |= ( portMPU_REGION_EXECUTE_NEVER );
- }
- /* SH. */
- if( ( xRegions[ ucIndex ].ulParameters & tskMPU_REGION_INNER_SHAREABLE ) != 0 )
- {
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 |= ( portMPU_REGION_INNER_SHAREABLE );
- }
- else if( ( xRegions[ ucIndex ].ulParameters & tskMPU_REGION_OUTER_SHAREABLE ) != 0 )
- {
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 |= ( portMPU_REGION_OUTER_SHAREABLE );
- }
- else
- {
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 |= ( portMPU_REGION_NON_SHAREABLE );
- }
- /* End Address. */
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrlarEl1 = ( ullRegionEndAddress ) |
- ( portMPU_PRLAR_EL1_REGION_ENABLE );
- /* Normal memory/ Device memory. */
- if( ( xRegions[ ucIndex ].ulParameters & tskMPU_REGION_DEVICE_MEMORY ) != 0 )
- {
- /* Attr1 in MAIR_EL1 is configured as device memory. */
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrlarEl1 |= portMPU_PRLAR_EL1_ATTR_INDEX1;
- }
- else
- {
- /* Attr0 in MAIR_EL1 is configured as normal memory. */
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrlarEl1 |= portMPU_PRLAR_EL1_ATTR_INDEX0;
- }
- }
- }
- else
- {
- /* Invalidate the region. */
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrbarEl1 = 0UL;
- xMPUSettings->xRegionsSettings[ ucRegionNumber ].ullPrlarEl1 = 0UL;
- }
- ucIndex++;
- }
- }
- /*-----------------------------------------------------------*/
- void vSetupMPU( void ) /* PRIVILEGED_FUNCTION */
- {
- #if defined( __ARMCC_VERSION )
- /* Declaration when these variable are defined in code instead of being
- * exported from linker scripts.
- */
- extern uint64_t * __privileged_functions_start__;
- extern uint64_t * __privileged_functions_end__;
- extern uint64_t * __syscalls_flash_start__;
- extern uint64_t * __syscalls_flash_end__;
- extern uint64_t * __unprivileged_flash_start__;
- extern uint64_t * __unprivileged_flash_end__;
- extern uint64_t * __privileged_sram_start__;
- extern uint64_t * __privileged_sram_end__;
- #else /* if defined( __ARMCC_VERSION ) */
- /* Declaration when these variable are exported from linker scripts. */
- extern uint64_t __privileged_functions_start__[];
- extern uint64_t __privileged_functions_end__[];
- extern uint64_t __syscalls_flash_start__[];
- extern uint64_t __syscalls_flash_end__[];
- extern uint64_t __unprivileged_flash_start__[];
- extern uint64_t __unprivileged_flash_end__[];
- extern uint64_t __privileged_sram_start__[];
- extern uint64_t __privileged_sram_end__[];
- #endif /* defined( __ARMCC_VERSION ) */
- /* The only permitted number of regions are 16 or 32. */
- configASSERT( ( configTOTAL_MPU_REGIONS == 16 ) || ( configTOTAL_MPU_REGIONS == 32 ) );
- /* MAIR_EL1 - Index 0. */
- uint64_t ullMairEl1RegValue = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_EL1_ATTR0_POS ) & portMPU_MAIR_EL1_ATTR0_MASK );
- /* MAIR_EL1 - Index 1. */
- ullMairEl1RegValue |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_EL1_ATTR1_POS ) & portMPU_MAIR_EL1_ATTR1_MASK );
- __asm volatile ( "msr MAIR_EL1, %0" : : "r" ( ullMairEl1RegValue ) );
- /* Setup privileged flash as Read Only so that privileged tasks can
- * read it but not modify.
- */
- uint64_t ullPrselrEl1RegValue = portPRIVILEGED_FLASH_REGION;
- __asm volatile ( "msr PRSELR_EL1, %0" : : "r" ( ullPrselrEl1RegValue ) );
- uint64_t ullPrbarEl1RegValue = ( ( ( uint64_t ) __privileged_functions_start__ ) & portMPU_PRBAR_EL1_ADDRESS_MASK ) |
- ( portMPU_REGION_NON_SHAREABLE ) |
- ( portMPU_REGION_PRIVILEGED_READ_ONLY );
- __asm volatile ( "msr PRBAR_EL1, %0" : : "r" ( ullPrbarEl1RegValue ) );
- uint64_t ullPrlarEl1RegValue = ( ( ( uint64_t ) __privileged_functions_end__ ) & portMPU_PRLAR_EL1_ADDRESS_MASK ) |
- ( portMPU_PRLAR_EL1_ATTR_INDEX0 ) |
- ( portMPU_PRLAR_EL1_REGION_ENABLE );
- __asm volatile ( "msr PRLAR_EL1, %0" : : "r" ( ullPrlarEl1RegValue ) );
- /* Setup unprivileged flash as Read Only by both privileged and
- * unprivileged tasks. All tasks can read it but no-one can modify.
- */
- ullPrselrEl1RegValue = portUNPRIVILEGED_FLASH_REGION;
- __asm volatile ( "msr PRSELR_EL1, %0" : : "r" ( ullPrselrEl1RegValue ) );
- ullPrbarEl1RegValue = ( ( ( uint64_t ) __unprivileged_flash_start__ ) & portMPU_PRBAR_EL1_ADDRESS_MASK ) |
- ( portMPU_REGION_NON_SHAREABLE ) |
- ( portMPU_REGION_READ_ONLY );
- __asm volatile ( "msr PRBAR_EL1, %0" : : "r" ( ullPrbarEl1RegValue ) );
- ullPrlarEl1RegValue = ( ( ( uint64_t ) __unprivileged_flash_end__ ) & portMPU_PRLAR_EL1_ADDRESS_MASK ) |
- ( portMPU_PRLAR_EL1_ATTR_INDEX0 ) |
- ( portMPU_PRLAR_EL1_REGION_ENABLE );
- __asm volatile ( "msr PRLAR_EL1, %0" : : "r" ( ullPrlarEl1RegValue ) );
- /* Setup unprivileged syscalls flash as Read Only by both privileged
- * and unprivileged tasks. All tasks can read it but no-one can modify.
- */
- ullPrselrEl1RegValue = portUNPRIVILEGED_SYSCALLS_REGION;
- __asm volatile ( "msr PRSELR_EL1, %0" : : "r" ( ullPrselrEl1RegValue ) );
- ullPrbarEl1RegValue = ( ( ( uint64_t ) __syscalls_flash_start__ ) & portMPU_PRBAR_EL1_ADDRESS_MASK ) |
- ( portMPU_REGION_NON_SHAREABLE ) |
- ( portMPU_REGION_READ_ONLY );
- __asm volatile ( "msr PRBAR_EL1, %0" : : "r" ( ullPrbarEl1RegValue ) );
- ullPrlarEl1RegValue = ( ( ( uint64_t ) __syscalls_flash_end__ ) & portMPU_PRLAR_EL1_ADDRESS_MASK ) |
- ( portMPU_PRLAR_EL1_ATTR_INDEX0 ) |
- ( portMPU_PRLAR_EL1_REGION_ENABLE );
- __asm volatile ( "msr PRLAR_EL1, %0" : : "r" ( ullPrlarEl1RegValue ) );
- /* Setup RAM containing kernel data for privileged access only. */
- ullPrselrEl1RegValue = portPRIVILEGED_RAM_REGION;
- __asm volatile ( "msr PRSELR_EL1, %0" : : "r" ( ullPrselrEl1RegValue ) );
- ullPrbarEl1RegValue = ( ( ( uint64_t ) __privileged_sram_start__ ) & portMPU_PRBAR_EL1_ADDRESS_MASK ) |
- ( portMPU_REGION_INNER_SHAREABLE ) |
- ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
- ( portMPU_REGION_EXECUTE_NEVER );
- __asm volatile ( "msr PRBAR_EL1, %0" : : "r" ( ullPrbarEl1RegValue ) );
- ullPrlarEl1RegValue = ( ( ( uint64_t ) __privileged_sram_end__ ) & portMPU_PRLAR_EL1_ADDRESS_MASK ) |
- ( portMPU_PRLAR_EL1_ATTR_INDEX0 ) |
- ( portMPU_PRLAR_EL1_REGION_ENABLE );
- __asm volatile ( "msr PRLAR_EL1, %0" : : "r" ( ullPrlarEl1RegValue ) );
- }
- /*-----------------------------------------------------------*/
- void vEnableMPU( void ) /* PRIVILEGED_FUNCTION */
- {
- uint64_t ullSctlrEl1RegValue;
- __asm volatile ( "mrs %0, SCTLR_EL1" : "=r" ( ullSctlrEl1RegValue ) );
- /* Enable the MPU. Also enable privileged access to the
- * background region.
- */
- ullSctlrEl1RegValue |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT );
- __asm volatile ( "msr SCTLR_EL1, %0" : : "r" ( ullSctlrEl1RegValue ) );
- /* Ensure the write to SCTLR_EL1 is committed before
- * returning.
- */
- __asm volatile ( "isb" );
- }
- /*-----------------------------------------------------------*/
- BaseType_t xPortIsTaskPrivileged( void ) /* PRIVILEGED_FUNCTION */
- {
- BaseType_t xTaskIsPrivileged = pdFALSE;
- #if ( configNUMBER_OF_CORES == 1 )
- extern TaskHandle_t pxCurrentTCB;
- xMPU_SETTINGS * pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
- #else
- extern TaskHandle_t pxCurrentTCBs[ configNUMBER_OF_CORES ];
- xMPU_SETTINGS * pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCBs[ portGET_CORE_ID_FROM_ISR() ] );
- #endif
- if( ( pxMpuSettings->ullTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
- {
- xTaskIsPrivileged = pdTRUE;
- }
- return xTaskIsPrivileged;
- }
- /*-----------------------------------------------------------*/
- static uint32_t prvGetRegionAccessPermissions( uint64_t ullPrbarEl1Value ) /* PRIVILEGED_FUNCTION */
- {
- uint32_t ulAccessPermissions = 0;
- if( ( ullPrbarEl1Value & portMPU_PRBAR_EL1_ACCESS_PERMISSIONS_MASK ) == portMPU_REGION_READ_ONLY )
- {
- ulAccessPermissions = tskMPU_READ_PERMISSION;
- }
- if( ( ullPrbarEl1Value & portMPU_PRBAR_EL1_ACCESS_PERMISSIONS_MASK ) == portMPU_REGION_READ_WRITE )
- {
- ulAccessPermissions = ( tskMPU_READ_PERMISSION | tskMPU_WRITE_PERMISSION );
- }
- return ulAccessPermissions;
- }
- /*-----------------------------------------------------------*/
- BaseType_t xPortIsAuthorizedToAccessBuffer( const void * pvBuffer,
- uint32_t ulBufferLength,
- uint32_t ulAccessRequested ) /* PRIVILEGED_FUNCTION */
- {
- uint32_t i;
- uint64_t ullBufferStartAddress, ullBufferEndAddress;
- BaseType_t xAccessGranted = pdFALSE;
- const xMPU_SETTINGS * xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
- if( xSchedulerRunning == pdFALSE )
- {
- /* Grant access to all the kernel objects before the scheduler
- * is started. It is necessary because there is no task running
- * yet and therefore, we cannot use the permissions of any
- * task. */
- xAccessGranted = pdTRUE;
- }
- else if( ( xTaskMpuSettings->ullTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
- {
- xAccessGranted = pdTRUE;
- }
- else
- {
- if( portADD_UINT64_WILL_OVERFLOW( ( ( uint64_t ) pvBuffer ), ( ulBufferLength - 1UL ) ) == pdFALSE )
- {
- ullBufferStartAddress = ( uint64_t ) pvBuffer;
- ullBufferEndAddress = ( ( ( uint64_t ) pvBuffer ) + ulBufferLength - 1UL );
- for( i = 0; i < portTOTAL_NUM_REGIONS; i++ )
- {
- /* Is the MPU region enabled? */
- if( ( xTaskMpuSettings->xRegionsSettings[ i ].ullPrlarEl1 & portMPU_PRLAR_EL1_REGION_ENABLE ) == portMPU_PRLAR_EL1_REGION_ENABLE )
- {
- if( portIS_ADDRESS_WITHIN_RANGE( ullBufferStartAddress,
- portEXTRACT_FIRST_ADDRESS_FROM_PRBAR_EL1( xTaskMpuSettings->xRegionsSettings[ i ].ullPrbarEl1 ),
- portEXTRACT_LAST_ADDRESS_FROM_PRLAR_EL1( xTaskMpuSettings->xRegionsSettings[ i ].ullPrlarEl1 ) ) &&
- portIS_ADDRESS_WITHIN_RANGE( ullBufferEndAddress,
- portEXTRACT_FIRST_ADDRESS_FROM_PRBAR_EL1( xTaskMpuSettings->xRegionsSettings[ i ].ullPrbarEl1 ),
- portEXTRACT_LAST_ADDRESS_FROM_PRLAR_EL1( xTaskMpuSettings->xRegionsSettings[ i ].ullPrlarEl1 ) ) &&
- portIS_AUTHORIZED( ulAccessRequested,
- prvGetRegionAccessPermissions( xTaskMpuSettings->xRegionsSettings[ i ].ullPrbarEl1 ) ) )
- {
- xAccessGranted = pdTRUE;
- break;
- }
- }
- }
- }
- }
- return xAccessGranted;
- }
- /*-----------------------------------------------------------*/
- void vSystemCallEnter( uint64_t * pullPrivilegedOnlyTaskStack,
- uint8_t ucSystemCallNumber ) /* PRIVILEGED_FUNCTION */
- {
- #if ( configNUMBER_OF_CORES == 1 )
- extern TaskHandle_t pxCurrentTCB;
- #else
- extern TaskHandle_t pxCurrentTCBs[ configNUMBER_OF_CORES ];
- #endif
- extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ];
- xMPU_SETTINGS * pxMpuSettings;
- uint64_t ullSystemCallLocation; /* Address where SVC was raised. */
- __asm volatile ( "MRS %0, ELR_EL1" : "=r" ( ullSystemCallLocation ) );
- #if defined( __ARMCC_VERSION )
- /* Declaration when these variable are defined in code instead of being
- * exported from linker scripts.
- */
- extern uint64_t * __syscalls_flash_start__;
- extern uint64_t * __syscalls_flash_end__;
- #else
- /* Declaration when these variable are exported from linker scripts. */
- extern uint64_t __syscalls_flash_start__[];
- extern uint64_t __syscalls_flash_end__[];
- #endif /* #if defined( __ARMCC_VERSION ) */
- #if ( configNUMBER_OF_CORES == 1 )
- pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
- #else
- pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCBs[ portGET_CORE_ID_FROM_ISR() ] );
- #endif
- /* Checks:
- * 1. SVC is raised from the system call section (i.e. application is
- * not raising SVC directly).
- * 2. We do not need to check that ucSystemCallNumber is within range
- * because the assembly SVC handler checks that before calling
- * this function.
- */
- if( ( ullSystemCallLocation >= ( uint64_t ) __syscalls_flash_start__ ) &&
- ( ullSystemCallLocation <= ( uint64_t ) __syscalls_flash_end__ ) &&
- ( uxSystemCallImplementations[ ucSystemCallNumber ] != 0 ) )
- {
- /* Store the value of the Link Register before the SVC was raised.
- * It contains the address of the caller of the System Call entry
- * point (i.e. the caller of the MPU_<API>). We need to restore it
- * when we exit from the system call.
- */
- pxMpuSettings->xSystemCallInfo.ullLinkRegisterAtSystemCallEntry = pullPrivilegedOnlyTaskStack[ portOFFSET_TO_LR ];
- /* Capture user-mode SP at system call entry. */
- uint64_t ullUserSpAtEntry;
- __asm volatile ( "MRS %0, SP_EL0" : "=r" ( ullUserSpAtEntry ) );
- pxMpuSettings->xSystemCallInfo.ullUserSPAtSystemCallEntry = ullUserSpAtEntry;
- /* Setup the MPU_<API> inputs, the system call stack, and SPSR. */
- __asm volatile (
- "MOV X0, %0 \n"
- "MOV X1, %1 \n"
- "MOV X2, %2 \n"
- "MOV X3, %3 \n"
- "MSR ELR_EL1, %4 \n"
- "MSR SP_EL0, %5 \n"
- "MSR SPSR_EL1, %6 \n"
- :
- : "r" ( pullPrivilegedOnlyTaskStack[ portOFFSET_TO_X0 ] ),
- "r" ( pullPrivilegedOnlyTaskStack[ portOFFSET_TO_X1 ] ),
- "r" ( pullPrivilegedOnlyTaskStack[ portOFFSET_TO_X2 ] ),
- "r" ( pullPrivilegedOnlyTaskStack[ portOFFSET_TO_X3 ] ),
- "r" ( ( uint64_t ) uxSystemCallImplementations[ ucSystemCallNumber ] ),
- "r" ( &( pxMpuSettings->ullContext[ MAX_CONTEXT_SIZE + configSYSTEM_CALL_STACK_SIZE ] ) ),
- "r" ( portINITIAL_PSTATE_EL1 )
- : "memory", "x0", "x1", "x2", "x3"
- );
- }
- }
- /*-----------------------------------------------------------*/
- void vRequestSystemCallExit( void ) /* __attribute__( ( naked ) ) PRIVILEGED_FUNCTION */
- {
- __asm volatile ( "svc %0 \n" ::"i" ( portSVC_SYSTEM_CALL_EXIT ) : "memory" );
- }
- /*-----------------------------------------------------------*/
- void vSystemCallExit( uint64_t ullSystemCallReturnValue ) /* PRIVILEGED_FUNCTION */
- {
- #if ( configNUMBER_OF_CORES == 1 )
- extern TaskHandle_t pxCurrentTCB;
- #else
- extern TaskHandle_t pxCurrentTCBs[ configNUMBER_OF_CORES ];
- #endif
- xMPU_SETTINGS * pxMpuSettings;
- uint64_t ullSystemCallLocation; /* Address where SVC was raised. */
- __asm volatile ( "MRS %0, ELR_EL1" : "=r" ( ullSystemCallLocation ) );
- #if defined( __ARMCC_VERSION )
- /* Declaration when these variable are defined in code instead of being
- * exported from linker scripts. */
- extern uint64_t * __privileged_functions_start__;
- extern uint64_t * __privileged_functions_end__;
- #else
- /* Declaration when these variable are exported from linker scripts. */
- extern uint64_t __privileged_functions_start__[];
- extern uint64_t __privileged_functions_end__[];
- #endif /* #if defined( __ARMCC_VERSION ) */
- #if ( configNUMBER_OF_CORES == 1 )
- pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCB );
- #else
- pxMpuSettings = xTaskGetMPUSettings( pxCurrentTCBs[ portGET_CORE_ID_FROM_ISR() ] );
- #endif
- /* Check:
- * SVC is raised from the privileged code (i.e. application is not
- * raising SVC directly). This SVC is only raised from
- * vRequestSystemCallExit which is in the privileged code section.
- */
- if( ( ullSystemCallLocation >= ( uint64_t ) __privileged_functions_start__ ) &&
- ( ullSystemCallLocation <= ( uint64_t ) __privileged_functions_end__ ) )
- {
- __asm volatile (
- "MSR ELR_EL1, %0 \n" /* Return to the MPU_<API> caller. */
- "MSR SP_EL0, %1 \n" /* Restore user SP saved at syscall entry. */
- "MSR SPSR_EL1, %3 \n" /* Ensure return to EL0. */
- "MOV X0, %2 \n" /* Move the system call return value to X0. */
- :
- : "r" ( pxMpuSettings->xSystemCallInfo.ullLinkRegisterAtSystemCallEntry ),
- "r" ( pxMpuSettings->xSystemCallInfo.ullUserSPAtSystemCallEntry ),
- "r" ( ullSystemCallReturnValue ),
- "r" ( ( uint64_t ) portINITIAL_PSTATE_EL0 )
- : "memory"
- );
- }
- }
- /*-----------------------------------------------------------*/
- #if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
- void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
- int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
- {
- uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
- xMPU_SETTINGS * xTaskMpuSettings;
- /* Calculate the Access Control List entry index and bit position
- * within that entry. */
- ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
- ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
- xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
- /* Set the bit corresponding to the kernel object to grant access. */
- xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] |= ( 1U << ulAccessControlListEntryBit );
- }
- /*-----------------------------------------------------------*/
- void vPortRevokeAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
- int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
- {
- uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
- xMPU_SETTINGS * xTaskMpuSettings;
- /* Calculate the Access Control List entry index and bit position
- * within that entry. */
- ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
- ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
- xTaskMpuSettings = xTaskGetMPUSettings( xInternalTaskHandle );
- /* Clear the bit corresponding to the kernel object to revoke access. */
- xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] &= ~( 1U << ulAccessControlListEntryBit );
- }
- /*-----------------------------------------------------------*/
- BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
- {
- uint32_t ulAccessControlListEntryIndex, ulAccessControlListEntryBit;
- BaseType_t xAccessGranted = pdFALSE;
- const xMPU_SETTINGS * xTaskMpuSettings;
- if( xSchedulerRunning == pdFALSE )
- {
- /* Grant access to all the kernel objects before the scheduler
- * is started. It is necessary because there is no task running
- * yet and therefore, we cannot use the permissions of any
- * task. */
- xAccessGranted = pdTRUE;
- }
- else
- {
- xTaskMpuSettings = xTaskGetMPUSettings( NULL ); /* Calling task's MPU settings. */
- ulAccessControlListEntryIndex = ( ( uint32_t ) lInternalIndexOfKernelObject / portACL_ENTRY_SIZE_BITS );
- ulAccessControlListEntryBit = ( ( uint32_t ) lInternalIndexOfKernelObject % portACL_ENTRY_SIZE_BITS );
- if( ( xTaskMpuSettings->ullTaskFlags & portTASK_IS_PRIVILEGED_FLAG ) == portTASK_IS_PRIVILEGED_FLAG )
- {
- xAccessGranted = pdTRUE;
- }
- else
- {
- if( ( xTaskMpuSettings->ulAccessControlList[ ulAccessControlListEntryIndex ] & ( 1U << ulAccessControlListEntryBit ) ) != 0 )
- {
- xAccessGranted = pdTRUE;
- }
- }
- }
- return xAccessGranted;
- }
- /*-----------------------------------------------------------*/
- #else /* configENABLE_ACCESS_CONTROL_LIST == 1 */
- BaseType_t xPortIsAuthorizedToAccessKernelObject( int32_t lInternalIndexOfKernelObject ) /* PRIVILEGED_FUNCTION */
- {
- ( void ) lInternalIndexOfKernelObject;
- /* If Access Control List feature is not used, all the tasks have
- * access to all the kernel objects. */
- return pdTRUE;
- }
- /*-----------------------------------------------------------*/
- #endif /* configENABLE_ACCESS_CONTROL_LIST == 1 */
- #endif /* #if ( configENABLE_MPU == 1 ) */
- BaseType_t xPortStartScheduler( void )
- {
- uint64_t ullAPSR;
- #if ( configASSERT_DEFINED == 1 )
- {
- volatile uint8_t ucOriginalPriority;
- volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
- volatile uint8_t ucMaxPriorityValue;
- /* Determine how many priority bits are implemented in the GIC.
- *
- * Save the interrupt priority value that is about to be clobbered. */
- ucOriginalPriority = *pucFirstUserPriorityRegister;
- /* Determine the number of priority bits available. First write to
- * all possible bits. */
- *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
- /* Read the value back to see how many bits stuck. */
- ucMaxPriorityValue = *pucFirstUserPriorityRegister;
- /* Shift to the least significant bits. */
- while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
- {
- ucMaxPriorityValue >>= ( uint8_t ) 0x01;
- }
- /* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
- * value. */
- configASSERT( ucMaxPriorityValue >= portLOWEST_INTERRUPT_PRIORITY );
- /* Restore the clobbered interrupt priority register to its original
- * value. */
- *pucFirstUserPriorityRegister = ucOriginalPriority;
- }
- #endif /* configASSERT_DEFINED */
- __asm volatile ( "MRS %0, CurrentEL" : "=r" ( ullAPSR ) );
- ullAPSR &= portAPSR_MODE_BITS_MASK;
- configASSERT( ullAPSR == portEL1 );
- #if ( configENABLE_MPU == 1 )
- {
- /* Setup the Memory Protection Unit (MPU). */
- vSetupMPU();
- }
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /* Interrupts are turned off in the CPU itself to ensure a tick does
- * not execute while the scheduler is being started. Interrupts are
- * automatically turned back on in the CPU when the first task starts
- * executing. */
- __asm volatile ( "MSR DAIFSET, #2\n"
- "DSB SY\n"
- "ISB SY\n" ::: "memory" );
- #if ( configNUMBER_OF_CORES > 1 )
- /* Start the timer that generates the tick ISR. */
- configSETUP_TICK_INTERRUPT();
- ucPrimaryCoreInitDoneFlag = 1;
- __asm volatile ( "SEV \n"
- "DSB SY \n"
- "ISB SY \n"
- ::: "memory" );
- /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
- * all elements of ucSecondaryCoresReadyFlags are set.
- */
- while( 1 )
- {
- BaseType_t xAllCoresReady = pdTRUE;
- for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ )
- {
- if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE )
- {
- xAllCoresReady = pdFALSE;
- break;
- }
- }
- if ( xAllCoresReady == pdTRUE )
- {
- break;
- }
- }
- #else /* if ( configNUMBER_OF_CORES > 1 ) */
- /* Start the timer that generates the tick ISR. */
- configSETUP_TICK_INTERRUPT();
- #endif /* if ( configNUMBER_OF_CORES > 1 ) */
- #if ( configENABLE_MPU == 1 )
- xSchedulerRunning = pdTRUE;
- /* Enable the Memory Protection Unit (MPU)
- * MPU is only enabled after the primary and secondary handshakes
- * are done as to prevent inconsistent MPU regions attributes across
- * different cores resulting in unupdated values of the handshake
- * flags.
- */
- vEnableMPU();
- #endif /* #if ( configENABLE_MPU == 1 ) */
- /* Start the first task executing. */
- vPortRestoreTaskContext();
- return 0;
- }
- /*-----------------------------------------------------------*/
- void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
- {
- /* Stub implementation for ports where there is nothing to return to
- * Artificially force an assert. */
- configASSERT( NULL );
- }
- /*-----------------------------------------------------------*/
- #if ( configNUMBER_OF_CORES == 1 )
- PRIVILEGED_FUNCTION void vPortEnterCritical( void )
- {
- /* Mask interrupts up to the max syscall interrupt priority. */
- uxPortSetInterruptMask();
- /* Now interrupts are disabled ullCriticalNesting can be accessed
- * directly. Increment ullCriticalNesting to keep a count of how many times
- * portENTER_CRITICAL() has been called. */
- ullCriticalNesting++;
- /* This is not the interrupt safe version of the enter critical function so
- * assert() if it is being called from an interrupt context. Only API
- * functions that end in "FromISR" can be used in an interrupt. Only assert if
- * the critical nesting count is 1 to protect against recursive calls if the
- * assert function also uses a critical section. */
- if( ullCriticalNesting == 1ULL )
- {
- configASSERT( ullPortInterruptNesting == 0 );
- }
- }
- /*-----------------------------------------------------------*/
- PRIVILEGED_FUNCTION void vPortExitCritical( void )
- {
- if( ullCriticalNesting > portNO_CRITICAL_NESTING )
- {
- /* Decrement the nesting count as the critical section is being
- * exited. */
- ullCriticalNesting--;
- /* If the nesting level has reached zero then all interrupt
- * priorities must be re-enabled. */
- if( ullCriticalNesting == portNO_CRITICAL_NESTING )
- {
- /* Critical nesting has reached zero so all interrupt priorities
- * should be unmasked. */
- portCLEAR_INTERRUPT_PRIORITIES_MASK();
- }
- }
- }
- #endif /* if ( configNUMBER_OF_CORES == 1 ) */
- /*-----------------------------------------------------------*/
- void FreeRTOS_Tick_Handler( void )
- {
- /* Must be the lowest possible priority. */
- uint64_t ullRunningInterruptPriority;
- __asm volatile ( "MRS %0, ICC_RPR_EL1" : "=r" ( ullRunningInterruptPriority ) );
- configASSERT( ullRunningInterruptPriority == ( portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
- /* Interrupts should not be enabled before this point. */
- #if ( configASSERT_DEFINED == 1 )
- {
- uint64_t ullMaskBits;
- __asm volatile ( "MRS %0, DAIF" : "=r" ( ullMaskBits )::"memory" );
- configASSERT( ( ullMaskBits & portDAIF_I ) != 0 );
- }
- #endif /* configASSERT_DEFINED */
- /* Set interrupt mask before altering scheduler structures. The tick
- * interrupt runs at the lowest priority, so interrupts cannot already be masked,
- * so there is no need to save and restore the current mask value. It is
- * necessary to turn off interrupts in the CPU itself while the ICCPMR is being
- * updated.
- */
- UBaseType_t uxInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
- #if ( configNUMBER_OF_CORES > 1 )
- UBaseType_t x = portENTER_CRITICAL_FROM_ISR();
- #endif /* if ( configNUMBER_OF_CORES > 1 ) */
- /* Increment the RTOS tick. */
- if( xTaskIncrementTick() != pdFALSE )
- {
- #if ( configNUMBER_OF_CORES == 1 )
- ullPortYieldRequired = pdTRUE;
- #else
- ullPortYieldRequired[ portGET_CORE_ID_FROM_ISR() ] = pdTRUE;
- #endif
- }
- #if ( configNUMBER_OF_CORES > 1 )
- portEXIT_CRITICAL_FROM_ISR(x);
- #endif /* if ( configNUMBER_OF_CORES > 1 ) */
- /* Ensure all interrupt priorities are active again. */
- portCLEAR_INTERRUPT_MASK_FROM_ISR( uxInterruptStatus );
- /* Ok to enable interrupts after the interrupt source has been cleared. */
- configCLEAR_TICK_INTERRUPT();
- }
- /*-----------------------------------------------------------*/
- #if ( configUSE_TASK_FPU_SUPPORT == portTASK_NO_FPU_CONTEXT_BY_DEFAULT )
- void vPortTaskUsesFPU( void )
- {
- /* A task is registering the fact that it needs an FPU context. Set the
- * FPU flag (which is saved as part of the task context). */
- #if ( configNUMBER_OF_CORES == 1 )
- ullPortTaskHasFPUContext = pdTRUE;
- #else
- ullPortTaskHasFPUContext[ portGET_CORE_ID() ] = pdTRUE;
- #endif
- /* Consider initialising the FPSR here - but probably not necessary in
- * AArch64. */
- }
- #endif /* configUSE_TASK_FPU_SUPPORT */
- /*-----------------------------------------------------------*/
- void vPortClearInterruptMask( UBaseType_t uxNewMaskValue )
- {
- if( uxNewMaskValue == portUNMASK_VALUE )
- {
- /* Unmask all interrupt priorities. */
- portCLEAR_INTERRUPT_PRIORITIES_MASK();
- }
- else
- {
- __asm volatile (
- "SVC %0 \n"
- :
- : "i" ( portSVC_UNMASK_INTERRUPTS )
- : "memory"
- );
- }
- }
- void vPortClearInterruptMaskFromISR( UBaseType_t uxNewMaskValue )
- {
- __asm volatile (
- "MSR DAIFSET, #2 \n"
- "DSB SY \n"
- "ISB SY \n"
- "MSR ICC_PMR_EL1, %0 \n"
- "DSB SY \n"
- "ISB SY \n"
- "MSR DAIFCLR, #2 \n"
- "DSB SY \n"
- "ISB SY \n"
- :
- : "r" ( uxNewMaskValue )
- );
- }
- /*-----------------------------------------------------------*/
- UBaseType_t uxPortSetInterruptMask( void )
- {
- UBaseType_t ullPMRValue;
- /* Use SVC so this can be called safely from EL0 tasks. */
- __asm volatile (
- "svc %1 \n"
- "mov %0, x0 \n"
- : "=r" ( ullPMRValue )
- : "i" ( portSVC_MASK_ALL_INTERRUPTS )
- : "x0", "memory"
- );
- return ullPMRValue;
- }
- /* EL1/ISR variant to avoid SVC from interrupt context. */
- UBaseType_t uxPortSetInterruptMaskFromISR( void )
- {
- UBaseType_t ullPMRValue;
- __asm volatile ( "MRS %0, ICC_PMR_EL1" : "=r" ( ullPMRValue ) );
- if( ullPMRValue != ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
- {
- __asm volatile ( "MSR DAIFSET, #2 \n"
- "DSB SY \n"
- "ISB SY \n"
- "MSR ICC_PMR_EL1, %0 \n"
- "DSB SY \n"
- "ISB SY \n"
- "MSR DAIFCLR, #2 \n"
- "DSB SY \n"
- "ISB SY \n"
- ::"r" ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) : "memory" );
- }
- return ullPMRValue;
- }
- /*-----------------------------------------------------------*/
- #if ( configASSERT_DEFINED == 1 )
- void vPortValidateInterruptPriority( void )
- {
- /* The following assertion will fail if a service routine (ISR) for
- * an interrupt that has been assigned a priority above
- * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
- * function. ISR safe FreeRTOS API functions must *only* be called
- * from interrupts that have been assigned a priority at or below
- * configMAX_SYSCALL_INTERRUPT_PRIORITY.
- *
- * Numerically low interrupt priority numbers represent logically high
- * interrupt priorities, therefore the priority of the interrupt must
- * be set to a value equal to or numerically *higher* than
- * configMAX_SYSCALL_INTERRUPT_PRIORITY.
- *
- * FreeRTOS maintains separate thread and ISR API functions to ensure
- * interrupt entry is as fast and simple as possible. */
- uint64_t ullRunningInterruptPriority;
- __asm volatile ( "MRS %0, ICC_RPR_EL1" : "=r" ( ullRunningInterruptPriority ) );
- configASSERT( ullRunningInterruptPriority >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
- }
- #endif /* configASSERT_DEFINED */
- /*-----------------------------------------------------------*/
- /*
- * 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
- * vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
- * it should never actually get called so its implementation contains a
- * call to configASSERT() that will always fail.
- *
- * If the application provides its own implementation of
- * vApplicationFPUSafeIRQHandler() then the implementation of
- * vApplicationIRQHandler() provided in portASM.S will save the FPU registers
- * before calling it.
- *
- * 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().
- */
- __attribute__( ( weak ) ) void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR )
- {
- ( void ) ulICCIAR;
- configASSERT( ( volatile void * ) NULL );
- }
- /*-----------------------------------------------------------*/
- #if ( configNUMBER_OF_CORES > 1 )
- /* Which core owns the lock? Keep in privileged, shareable RAM. */
- PRIVILEGED_DATA volatile uint64_t ullOwnedByCore[ portMAX_CORE_COUNT ];
- /* Lock count a core owns. */
- PRIVILEGED_DATA volatile uint64_t ullRecursionCountByLock[ eLockCount ];
- /* Index 0 is used for ISR lock and Index 1 is used for task lock. */
- PRIVILEGED_DATA uint32_t ulGateWord[ eLockCount ];
- void vInterruptCore( uint32_t ulInterruptID, uint8_t ucCoreID )
- {
- uint64_t ulRegVal = 0;
- uint32_t ulCoreMask = ( 1UL << ucCoreID );
- ulRegVal |= ( (ulCoreMask & 0xFFFF) | ( ( ulInterruptID & 0xF ) << 24U ) );
- __asm volatile (
- "str x0, [ sp, #-0x10 ]! \n"
- "mov x0, %0 \n"
- "svc %1 \n"
- "ldr x0, [ sp ], # 0x10 \n"
- :
- : "r" ( ulRegVal ), "i" ( portSVC_INTERRUPT_CORE )
- : "memory", "w1"
- );
- }
- /*-----------------------------------------------------------*/
- static inline void prvSpinUnlock( uint32_t * ulLock )
- {
- /* Conservative unlock: preserve original barriers for broad HW/FVP. */
- __asm volatile (
- "dmb sy \n"
- "mov w1, #0 \n"
- "str w1, [%x0] \n"
- "sev \n"
- "dsb sy \n"
- "isb sy \n"
- :
- : "r" ( ulLock )
- : "memory", "w1"
- );
- }
- /*-----------------------------------------------------------*/
- static inline uint32_t prvSpinTrylock( uint32_t * ulLock )
- {
- /*
- * Conservative LDXR/STXR trylock:
- * - Return 1 immediately if busy, clearing exclusive state (CLREX).
- * - Retry STXR only on spurious failure when observed free.
- * - DMB on success to preserve expected acquire semantics.
- */
- register uint32_t ulRet;
- __asm volatile (
- "1: \n"
- "ldxr w1, [%x1] \n"
- "cbnz w1, 2f \n" /* Busy -> return 1 */
- "mov w2, #1 \n"
- "stxr w3, w2, [%x1] \n" /* w3 = status */
- "cbnz w3, 1b \n" /* Retry on STXR failure */
- "dmb sy \n" /* Acquire barrier on success */
- "mov %w0, #0 \n" /* Success */
- "b 3f \n"
- "2: \n"
- "clrex \n" /* Clear monitor when busy */
- "mov %w0, #1 \n" /* Busy */
- "3: \n"
- : "=r" ( ulRet )
- : "r" ( ulLock )
- : "memory", "w1", "w2", "w3"
- );
- return ulRet;
- }
- /*-----------------------------------------------------------*/
- /* Read 64b value shared between cores. */
- static inline uint64_t prvGet64( volatile uint64_t * x )
- {
- __asm( "dsb sy" );
- return *x;
- }
- /*-----------------------------------------------------------*/
- /* Write 64b value shared between cores. */
- static inline void prvSet64( volatile uint64_t * x,
- uint64_t value )
- {
- *x = value;
- __asm( "dsb sy" );
- }
- /*-----------------------------------------------------------*/
- void vPortRecursiveLock( uint8_t ucCoreID,
- ePortRTOSLock eLockNum,
- BaseType_t uxAcquire )
- {
- /* Validate the core ID and lock number. */
- configASSERT( ucCoreID < portMAX_CORE_COUNT );
- configASSERT( eLockNum < eLockCount );
- uint32_t ulLockBit = 1u << eLockNum;
- /* Lock acquire */
- if( uxAcquire )
- {
- /* Check if spinlock is available.
- * If spinlock is not available check if the core owns the lock.
- * If the core owns the lock wait increment the lock count by the core.
- * If core does not own the lock wait for the spinlock.
- */
- if( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
- {
- /* Check if the core owns the spinlock. */
- if( prvGet64( &ullOwnedByCore[ ucCoreID ] ) & ulLockBit )
- {
- configASSERT( prvGet64( &ullRecursionCountByLock[ eLockNum ] ) != 255u );
- prvSet64( &ullRecursionCountByLock[ eLockNum ], ( prvGet64( &ullRecursionCountByLock[ eLockNum ] ) + 1 ) );
- return;
- }
- /* Preload the gate word into the cache. */
- uint32_t dummy = ulGateWord[ eLockNum ];
- dummy++;
- while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
- {
- /* Follow Arm's recommended way of sleeping
- * sevl is used to prime the wait loop.
- * The first wfe wakes immediately because sevl has set the flag.
- * Check the lock, if it's not available, issue a second wfe to sleep.
- * This guarantees the core actually goes to sleep.
- */
- __asm volatile (
- "sevl \n"
- "1: wfe \n"
- "ldr w2, [%x0] \n"
- "cbnz w2, 1b \n"
- :
- : "r" ( &ulGateWord[ eLockNum ] )
- : "memory", "w2"
- );
- }
- }
- /* Add barrier to ensure lock is taken before we proceed. */
- __asm__ __volatile__ ( "dmb sy" ::: "memory" );
- /* Assert the lock count is 0 when the spinlock is free and is acquired. */
- configASSERT( prvGet64( &ullRecursionCountByLock[ eLockNum ] ) == 0 );
- /* Set lock count as 1. */
- prvSet64( &ullRecursionCountByLock[ eLockNum ], 1 );
- /* Set ullOwnedByCore. */
- prvSet64( &ullOwnedByCore[ ucCoreID ], ( prvGet64( &ullOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
- }
- /* Lock release. */
- else
- {
- /* Assert the lock is not free already. */
- configASSERT( ( prvGet64( &ullOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
- configASSERT( prvGet64( &ullRecursionCountByLock[ eLockNum ] ) != 0 );
- /* Reduce ullRecursionCountByLock by 1. */
- prvSet64( &ullRecursionCountByLock[ eLockNum ], ( prvGet64( &ullRecursionCountByLock[ eLockNum ] ) - 1 ) );
- if( !prvGet64( &ullRecursionCountByLock[ eLockNum ] ) )
- {
- prvSet64( &ullOwnedByCore[ ucCoreID ], ( prvGet64( &ullOwnedByCore[ ucCoreID ] ) & ~ulLockBit ) );
- prvSpinUnlock( &ulGateWord[ eLockNum ] );
- /* Add barrier to ensure lock status is reflected before we proceed. */
- __asm__ __volatile__ ( "dmb sy" ::: "memory" );
- }
- }
- }
- /*-----------------------------------------------------------*/
- uint8_t ucPortGetCoreID( void )
- {
- /* Use SVC to obtain the core ID in a way that is safe when called
- * from EL0 tasks. ISRs and EL1 code should use
- * ucPortGetCoreIDFromIsr()/portGET_CORE_ID_FROM_ISR().
- */
- uint8_t ucCoreID;
- __asm volatile (
- "svc %1 \n"
- "mov %w0, w0 \n"
- : "=r" ( ucCoreID )
- : "i" ( portSVC_GET_CORE_ID )
- : "x0", "memory"
- );
- return ucCoreID;
- }
- /*-----------------------------------------------------------*/
- uint8_t ucPortGetCoreIDFromIsr ( void ) /* PRIVILEGED_FUNCTION */
- {
- uint64_t ullMpidrEl1;
- __asm volatile ( "MRS %0, MPIDR_EL1" : "=r" ( ullMpidrEl1 ) );
- return ( uint8_t ) ( ullMpidrEl1 & 0xff );
- }
- /*------------------------------------------------------------*/
- void FreeRTOS_SGI_Handler( void )
- {
- /* Must be the lowest possible priority. */
- uint64_t ullRunningInterruptPriority;
- __asm volatile ( "MRS %0, ICC_RPR_EL1" : "=r" ( ullRunningInterruptPriority ) );
- configASSERT( ullRunningInterruptPriority == ( portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
- /* Interrupts should not be enabled before this point. */
- #if ( configASSERT_DEFINED == 1 )
- {
- uint64_t ullMaskBits;
- __asm volatile ( "mrs %0, DAIF" : "=r" ( ullMaskBits )::"memory" );
- configASSERT( ( ullMaskBits & portDAIF_I ) != 0 );
- }
- #endif /* configASSERT_DEFINED */
- /* Set interrupt mask before altering scheduler structures. The SGI
- * interrupt runs at the lowest priority, so interrupts cannot already be masked,
- * so there is no need to save and restore the current mask value. It is
- * necessary to turn off interrupts in the CPU itself while the ICCPMR is being
- * updated.
- */
- UBaseType_t uxInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
- UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
- #if ( configNUMBER_OF_CORES == 1 )
- ullPortYieldRequired = pdTRUE;
- #else
- ullPortYieldRequired[ portGET_CORE_ID_FROM_ISR() ] = pdTRUE;
- #endif
- portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
- portCLEAR_INTERRUPT_MASK_FROM_ISR( uxInterruptStatus );
- }
- /*-----------------------------------------------------------*/
- #endif /* if( configNUMBER_OF_CORES > 1 ) */
|