mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-04-03 04:27:39 -04:00
Add Multicore SMP on Armv8-M ports (#1385)
* ARMv8-M: Add SMP support to CM33 NTZ non-MPU port * Enable SMP for Arm Cortex-M33 NTZ port for GCC, ArmClang, and IAR toolchains. * Add per-core scheduler/port state: critical nesting. * Introduce spinlocks and inter-core yield/wakeup (SEV/WFE) plus primary/secondary core bring-up sync. * Update PendSV (i.e., context switch assembly) for core-safe preemption and restore paths. * Extend port macros/hooks for SMP in portmacrocommon.h, single-core builds remain unchanged. * Add the SMP boot sequence along with the necessary steps to enable SMP on Armv8-M based ports. This should help developers understand the requirements and process for enabling SMP on their Armv8-M based applications. * Update the kernel checker script to accept comma separated years in the copyright header. Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com> * Armv8-M: Copy SMP changes to all Armv8-M based ports This commit executes the `copy_files.py` python script to copy the changes applied in the previous commit (i.e., SMP changes) to all the Armv8-M based ports. Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com> --------- Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com>
This commit is contained in:
parent
c5c6f1514c
commit
f965eda041
121 changed files with 15014 additions and 4213 deletions
1
.github/.cSpellWords.txt
vendored
1
.github/.cSpellWords.txt
vendored
|
|
@ -433,6 +433,7 @@ LDRAS
|
||||||
ldrb
|
ldrb
|
||||||
ldrbs
|
ldrbs
|
||||||
LDRBS
|
LDRBS
|
||||||
|
ldrex
|
||||||
LDRNE
|
LDRNE
|
||||||
ldsr
|
ldsr
|
||||||
ldxr
|
ldxr
|
||||||
|
|
|
||||||
4
.github/scripts/kernel_checker.py
vendored
4
.github/scripts/kernel_checker.py
vendored
|
|
@ -2,6 +2,7 @@
|
||||||
#/*
|
#/*
|
||||||
# * FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
# * FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
# * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
# * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
# * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
# *
|
# *
|
||||||
# * SPDX-License-Identifier: MIT
|
# * SPDX-License-Identifier: MIT
|
||||||
# *
|
# *
|
||||||
|
|
@ -157,9 +158,10 @@ KERNEL_HEADER = [
|
||||||
|
|
||||||
|
|
||||||
FREERTOS_COPYRIGHT_REGEX = r"^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright \(C\) 20\d\d Amazon.com, Inc. or its affiliates. All Rights Reserved\.( \*\/)?$"
|
FREERTOS_COPYRIGHT_REGEX = r"^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright \(C\) 20\d\d Amazon.com, Inc. or its affiliates. All Rights Reserved\.( \*\/)?$"
|
||||||
|
ARM_COLLAB_YEAR_REGEX = r"20\d\d(?:-20\d\d|, 20\d\d)?"
|
||||||
|
|
||||||
FREERTOS_ARM_COLLAB_COPYRIGHT_REGEX = r"(^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright \(C\) 20\d\d Amazon.com, Inc. or its affiliates. All Rights Reserved\.( \*\/)?$)|" + \
|
FREERTOS_ARM_COLLAB_COPYRIGHT_REGEX = r"(^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright \(C\) 20\d\d Amazon.com, Inc. or its affiliates. All Rights Reserved\.( \*\/)?$)|" + \
|
||||||
r"(^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright 20\d\d(-20\d\d)? Arm Limited and/or its affiliates( +<open-source-office@arm\.com>)?( \*\/)?$)|" + \
|
rf"(^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright { ARM_COLLAB_YEAR_REGEX } Arm Limited and/or its affiliates( +<open-source-office@arm\.com>)?( \*\/)?$)|" + \
|
||||||
r"(^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright \(c\) 20\d\d(-20\d\d)? Arm Technology \(China\) Co., Ltd.All Rights Reserved\.( \*\/)?$)|" + \
|
r"(^(;|#)?( *(\/\*|\*|#|\/\/))? Copyright \(c\) 20\d\d(-20\d\d)? Arm Technology \(China\) Co., Ltd.All Rights Reserved\.( \*\/)?$)|" + \
|
||||||
r"(^(;|#)?( *(\/\*|\*|#|\/\/))? <open-source-office@arm\.com>( \*\/)?$)"
|
r"(^(;|#)?( *(\/\*|\*|#|\/\/))? <open-source-office@arm\.com>( \*\/)?$)"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
This directory tree contains the master copy of the FreeRTOS Armv8-M and
|
This directory tree contains the master copy of the FreeRTOS Armv8-M and
|
||||||
Armv8.1-M ports.
|
Armv8.1-M ports.
|
||||||
Do not use the files located here! These file are copied into separate
|
Do not use the files located here! These files are copied into separate
|
||||||
FreeRTOS/Source/portable/[compiler]/ARM_[CM23|CM33|CM52|CM55|CM85|STAR_MC3]_NNN directories
|
FreeRTOS/Source/portable/[compiler]/ARM_[CM23|CM33|CM52|CM55|CM85|STAR_MC3]_NNN directories
|
||||||
prior to each FreeRTOS release.
|
prior to each FreeRTOS release.
|
||||||
|
|
||||||
|
|
@ -9,3 +9,54 @@ FreeRTOS/Source/portable/[compiler]/ARM_[CM23|CM33|CM52|CM55|CM85|STAR_MC3] dire
|
||||||
|
|
||||||
If your Armv8-M/Armv8.1-M application does not use TrustZone then use the files from
|
If your Armv8-M/Armv8.1-M application does not use TrustZone then use the files from
|
||||||
the FreeRTOS/Source/portable/[compiler]/ARM_[CM23|CM33|CM52|CM55|CM85|STAR_MC3]_NTZ directories.
|
the FreeRTOS/Source/portable/[compiler]/ARM_[CM23|CM33|CM52|CM55|CM85|STAR_MC3]_NTZ directories.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The Armv8-M ports support SMP (multicore) systems when both MPU and TrustZone are disabled.
|
||||||
|
However, this has only been validated on Arm Cortex-M33 Non-TrustZone Non-MPU port.
|
||||||
|
|
||||||
|
SMP Boot Sequence
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
Primary core flow:
|
||||||
|
|
||||||
|
1. Perform core-specific and shared initialization (e.g., zero-initialize `.bss`).
|
||||||
|
2. Jump to `main()`, create user tasks, optionally pin tasks to specific cores.
|
||||||
|
3. Call `vTaskStartScheduler()` which invokes `xPortStartScheduler()`.
|
||||||
|
4. `xPortStartScheduler()` configures the primary core tick timer and signals secondary cores that shared init is complete using the `ucPrimaryCoreInitDoneFlag` variable.
|
||||||
|
5. Call the application-defined `configWAKE_SECONDARY_CORES` function.
|
||||||
|
6. Wait until all secondary cores report as brought up.
|
||||||
|
7. Once all cores are up, call `vStartFirstTask()` to schedule the first task on the primary core.
|
||||||
|
|
||||||
|
Secondary core flow:
|
||||||
|
|
||||||
|
1. Perform core-specific initialization.
|
||||||
|
2. Wait until the primary core signals that shared initialization has completed (that is, `ucPrimaryCoreInitDoneFlag` is set to 1). Once this occurs,
|
||||||
|
the application-defined `configWAKE_SECONDARY_CORES` function is invoked by the primary core to carry out the subsequent steps.
|
||||||
|
3. Program the inter-processor signaling mechanism (e.g., Arm Doorbell Mechanism) to be used by the kernel to interrupt that core and request that it perform a context switch.
|
||||||
|
4. Call `vPortConfigureInterruptPriorities` function to setup per core interrupt priorities.
|
||||||
|
5. If Pointer Authentication (PAC) or Branch Target Identification (BTI) is supported, call `vConfigurePACBTI` with `pdTRUE` as the input parameter to configure the per-core special-purpose CONTROL register
|
||||||
|
with the appropriate PACBTI settings.
|
||||||
|
6. Signal the primary that this secondary is online and ready by setting its flag in the `ucSecondaryCoresReadyFlags` array.
|
||||||
|
7. Issue an SVC with immediate value `102` (portSVC_START_SCHEDULER), which will call `vRestoreContextOfFirstTask()` to start scheduling on this core.
|
||||||
|
|
||||||
|
|
||||||
|
Inter-core notification
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
On SMP systems the application must provide an implementation of the `vInterruptCore( uint8_t ucCoreID )` function. The kernel calls this function
|
||||||
|
to interrupt another core and request that it perform a context switch (e.g., when a higher-priority task becomes ready on that core).
|
||||||
|
|
||||||
|
Typical platform implementation: write a doorbell flag/bit or other inter-processor signaling register targeting `ucCoreID`. This should cause a
|
||||||
|
"doorbell" (or equivalent) IRQ on the secondary core. In the secondary core’s doorbell IRQ handler, check the reason for the interrupt and, if it is a
|
||||||
|
schedule request, trigger a context switch (i.e., by calling `portYIELD_FROM_ISR`).
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* `vInterruptCore` is declared weak in the port so that platforms can override it. If your hardware lacks a dedicated doorbell, use any available
|
||||||
|
inter-core interrupt/messaging mechanism to achieve the same effect.
|
||||||
|
|
||||||
|
* The application must define `configCORE_ID_REGISTER`, usually in `FreeRTOSConfig.h` to the memory-mapped address of the platform register used
|
||||||
|
to read the current core ID. The port reads this register to determine the executing core and to index per-core scheduler state.
|
||||||
|
|
||||||
|
* The application must define `configWAKE_SECONDARY_CORES`, usually in `FreeRTOSConfig.h`, to point to the application/platform-specific function
|
||||||
|
that wakes up and make the secondary cores ready after the primary core completes initialisation.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 1
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -41,7 +40,15 @@ files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler.
|
||||||
#define configUSE_MPU_WRAPPERS_V1 0
|
#define configUSE_MPU_WRAPPERS_V1 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configNUMBER_OF_CORES
|
||||||
|
#define configNUMBER_OF_CORES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
EXTERN pxCurrentTCB
|
EXTERN pxCurrentTCB
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
EXTERN pxCurrentTCBs
|
||||||
|
#endif
|
||||||
EXTERN vTaskSwitchContext
|
EXTERN vTaskSwitchContext
|
||||||
EXTERN vPortSVCHandler_C
|
EXTERN vPortSVCHandler_C
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -169,8 +176,15 @@ vRestoreContextOfFirstTask:
|
||||||
#else /* configENABLE_MPU */
|
#else /* configENABLE_MPU */
|
||||||
|
|
||||||
vRestoreContextOfFirstTask:
|
vRestoreContextOfFirstTask:
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulFirstTaskLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -193,6 +207,13 @@ vRestoreContextOfFirstTask:
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
bx r2 /* Finally, branch to EXC_RETURN. */
|
bx r2 /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulFirstTaskLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -377,20 +398,37 @@ PendSV_Handler:
|
||||||
clrm {r1-r4} /* Clear r1-r4. */
|
clrm {r1-r4} /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
str r0, [r1] /* Save the new top of stack in TCB. */
|
str r0, [r1] /* Save the new top of stack in TCB. */
|
||||||
|
|
||||||
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
dsb
|
dsb
|
||||||
isb
|
isb
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
mov r0, r2 /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
bl vTaskSwitchContext
|
bl vTaskSwitchContext
|
||||||
mov r0, #0 /* r0 = 0. */
|
mov r0, #0 /* r0 = 0. */
|
||||||
msr basepri, r0 /* Enable interrupts. */
|
msr basepri, r0 /* Enable interrupts. */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -413,6 +451,13 @@ PendSV_Handler:
|
||||||
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
||||||
msr psp, r0 /* Remember the new top of stack for the task. */
|
msr psp, r0 /* Remember the new top of stack for the task. */
|
||||||
bx r3
|
bx r3
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulPendSVLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 1
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 1
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -134,8 +133,21 @@
|
||||||
(
|
(
|
||||||
" .syntax unified \n"
|
" .syntax unified \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulFirstTaskLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -158,6 +170,14 @@
|
||||||
" mov r0, #0 \n"
|
" mov r0, #0 \n"
|
||||||
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" \n"
|
||||||
|
" .align 4 \n"
|
||||||
|
"ulFirstTaskLiteralPool: \n"
|
||||||
|
" .word %c0 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" (configCORE_ID_REGISTER)
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,20 +442,43 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
" clrm {r1-r4} \n" /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
" \n"
|
" \n"
|
||||||
|
/*
|
||||||
|
* The SMP-specific logic below is derived from the Raspberry Pi
|
||||||
|
* implementation in the FreeRTOS-Kernel-Community-Supported-Ports project.
|
||||||
|
* Source: GCC/RP2350_ARM_NTZ/non_secure/portasm.c
|
||||||
|
* Upstream commit: 8b2955f6d97bf4cd582db9f5b62d9eb1587b76d7
|
||||||
|
*/
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
|
||||||
" \n"
|
" \n"
|
||||||
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
|
||||||
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
" msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
" dsb \n"
|
" dsb \n"
|
||||||
" isb \n"
|
" isb \n"
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
" mov r0, r2 \n" /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" bl vTaskSwitchContext \n"
|
" bl vTaskSwitchContext \n"
|
||||||
" mov r0, #0 \n" /* r0 = 0. */
|
" mov r0, #0 \n" /* r0 = 0. */
|
||||||
" msr basepri, r0 \n" /* Enable interrupts. */
|
" msr basepri, r0 \n" /* Enable interrupts. */
|
||||||
" \n"
|
" \n"
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
" ldr r1, =ulPendSVLiteralPool \n" /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
" ldmia r1!, {r2, r3} \n"
|
||||||
|
" ldr r2, [r2] \n" /* r2 = Core Id */
|
||||||
|
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
" \n"
|
" \n"
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -458,7 +501,16 @@ void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __att
|
||||||
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
|
||||||
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
|
||||||
" bx r3 \n"
|
" bx r3 \n"
|
||||||
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
" .align 4 \n"
|
||||||
|
" ulPendSVLiteralPool: \n"
|
||||||
|
" .word %c1 \n" /* CORE_ID_REGISTER */
|
||||||
|
" .word pxCurrentTCBs \n"
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configCORE_ID_REGISTER )
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
:: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2026 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __attribute__( ( used ) )
|
#define portDONT_DISCARD __attribute__( ( used ) )
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
#define portHAS_ARMV8M_MAIN_EXTENSION 0
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -41,7 +40,15 @@ files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler.
|
||||||
#define configUSE_MPU_WRAPPERS_V1 0
|
#define configUSE_MPU_WRAPPERS_V1 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configNUMBER_OF_CORES
|
||||||
|
#define configNUMBER_OF_CORES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
EXTERN pxCurrentTCB
|
EXTERN pxCurrentTCB
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
EXTERN pxCurrentTCBs
|
||||||
|
#endif
|
||||||
EXTERN vTaskSwitchContext
|
EXTERN vTaskSwitchContext
|
||||||
EXTERN vPortSVCHandler_C
|
EXTERN vPortSVCHandler_C
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -169,8 +176,15 @@ vRestoreContextOfFirstTask:
|
||||||
#else /* configENABLE_MPU */
|
#else /* configENABLE_MPU */
|
||||||
|
|
||||||
vRestoreContextOfFirstTask:
|
vRestoreContextOfFirstTask:
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulFirstTaskLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -193,6 +207,13 @@ vRestoreContextOfFirstTask:
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
bx r2 /* Finally, branch to EXC_RETURN. */
|
bx r2 /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulFirstTaskLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -377,20 +398,37 @@ PendSV_Handler:
|
||||||
clrm {r1-r4} /* Clear r1-r4. */
|
clrm {r1-r4} /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
str r0, [r1] /* Save the new top of stack in TCB. */
|
str r0, [r1] /* Save the new top of stack in TCB. */
|
||||||
|
|
||||||
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
dsb
|
dsb
|
||||||
isb
|
isb
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
mov r0, r2 /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
bl vTaskSwitchContext
|
bl vTaskSwitchContext
|
||||||
mov r0, #0 /* r0 = 0. */
|
mov r0, #0 /* r0 = 0. */
|
||||||
msr basepri, r0 /* Enable interrupts. */
|
msr basepri, r0 /* Enable interrupts. */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -413,6 +451,13 @@ PendSV_Handler:
|
||||||
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
||||||
msr psp, r0 /* Remember the new top of stack for the task. */
|
msr psp, r0 /* Remember the new top of stack for the task. */
|
||||||
bx r3
|
bx r3
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulPendSVLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 1
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -41,7 +40,15 @@ files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler.
|
||||||
#define configUSE_MPU_WRAPPERS_V1 0
|
#define configUSE_MPU_WRAPPERS_V1 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configNUMBER_OF_CORES
|
||||||
|
#define configNUMBER_OF_CORES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
EXTERN pxCurrentTCB
|
EXTERN pxCurrentTCB
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
EXTERN pxCurrentTCBs
|
||||||
|
#endif
|
||||||
EXTERN vTaskSwitchContext
|
EXTERN vTaskSwitchContext
|
||||||
EXTERN vPortSVCHandler_C
|
EXTERN vPortSVCHandler_C
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -169,8 +176,15 @@ vRestoreContextOfFirstTask:
|
||||||
#else /* configENABLE_MPU */
|
#else /* configENABLE_MPU */
|
||||||
|
|
||||||
vRestoreContextOfFirstTask:
|
vRestoreContextOfFirstTask:
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulFirstTaskLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -193,6 +207,13 @@ vRestoreContextOfFirstTask:
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
bx r2 /* Finally, branch to EXC_RETURN. */
|
bx r2 /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulFirstTaskLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -377,20 +398,37 @@ PendSV_Handler:
|
||||||
clrm {r1-r4} /* Clear r1-r4. */
|
clrm {r1-r4} /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
str r0, [r1] /* Save the new top of stack in TCB. */
|
str r0, [r1] /* Save the new top of stack in TCB. */
|
||||||
|
|
||||||
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
dsb
|
dsb
|
||||||
isb
|
isb
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
mov r0, r2 /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
bl vTaskSwitchContext
|
bl vTaskSwitchContext
|
||||||
mov r0, #0 /* r0 = 0. */
|
mov r0, #0 /* r0 = 0. */
|
||||||
msr basepri, r0 /* Enable interrupts. */
|
msr basepri, r0 /* Enable interrupts. */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -413,6 +451,13 @@ PendSV_Handler:
|
||||||
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
||||||
msr psp, r0 /* Remember the new top of stack for the task. */
|
msr psp, r0 /* Remember the new top of stack for the task. */
|
||||||
bx r3
|
bx r3
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulPendSVLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -52,6 +53,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 0
|
#define portARMV8M_MINOR_VERSION 0
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024-2025 Arm Limited and/or its affiliates
|
* Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +440,11 @@ static void prvTaskExitError( void );
|
||||||
*
|
*
|
||||||
* @return CONTROL register value according to the configured PACBTI option.
|
* @return CONTROL register value according to the configured PACBTI option.
|
||||||
*/
|
*/
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -535,6 +538,18 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* configENABLE_MPU == 1 */
|
#endif /* configENABLE_MPU == 1 */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Platform/Application-defined function that wakes up the secondary cores.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if the secondary cores were successfully woken up.
|
||||||
|
* pdFALSE otherwise.
|
||||||
|
*/
|
||||||
|
extern BaseType_t configWAKE_SECONDARY_CORES( void );
|
||||||
|
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -550,7 +565,15 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) PRIV
|
||||||
* @brief Each task maintains its own interrupt status in the critical nesting
|
* @brief Each task maintains its own interrupt status in the critical nesting
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0UL;
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulCriticalNestings[ 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 indicate that the primary core has completed its initialisation. */
|
||||||
|
PRIVILEGED_DATA volatile uint8_t ucPrimaryCoreInitDoneFlag = 0;
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
|
||||||
#if ( configENABLE_TRUSTZONE == 1 )
|
#if ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
|
||||||
|
|
@ -853,7 +876,11 @@ static void prvTaskExitError( void )
|
||||||
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
* should instead call vTaskDelete( NULL ). Artificially force an assert()
|
||||||
* to be triggered if configASSERT() is defined, then stop here so
|
* to be triggered if configASSERT() is defined, then stop here so
|
||||||
* application writers can catch the error. */
|
* application writers can catch the error. */
|
||||||
configASSERT( ulCriticalNesting == ~0UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == ~0UL );
|
||||||
|
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == ~0UL );
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
|
||||||
while( ulDummy == 0 )
|
while( ulDummy == 0 )
|
||||||
|
|
@ -1017,28 +1044,29 @@ void vPortYield( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
{
|
void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
portDISABLE_INTERRUPTS();
|
|
||||||
ulCriticalNesting++;
|
|
||||||
|
|
||||||
/* Barriers are normally not required but do ensure the code is
|
|
||||||
* completely within the specified behaviour for the architecture. */
|
|
||||||
__asm volatile ( "dsb" ::: "memory" );
|
|
||||||
__asm volatile ( "isb" );
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
|
||||||
{
|
|
||||||
configASSERT( ulCriticalNesting );
|
|
||||||
ulCriticalNesting--;
|
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 )
|
|
||||||
{
|
{
|
||||||
portENABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
|
ulCriticalNesting++;
|
||||||
|
/* Barriers are normally not required but do ensure the code is
|
||||||
|
* completely within the specified behaviour for the architecture. */
|
||||||
|
__asm volatile ( "dsb" ::: "memory" );
|
||||||
|
__asm volatile ( "isb" );
|
||||||
}
|
}
|
||||||
}
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
configASSERT( ulCriticalNesting );
|
||||||
|
ulCriticalNesting--;
|
||||||
|
|
||||||
|
if( ulCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configNUMBER_OF_CORES == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
|
@ -1046,6 +1074,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
uint32_t ulPreviousMask;
|
uint32_t ulPreviousMask;
|
||||||
|
|
||||||
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
UBaseType_t uxSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
traceISR_ENTER();
|
traceISR_ENTER();
|
||||||
{
|
{
|
||||||
/* Increment the RTOS tick. */
|
/* Increment the RTOS tick. */
|
||||||
|
|
@ -1060,6 +1092,10 @@ void SysTick_Handler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
traceISR_EXIT();
|
traceISR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -1548,7 +1584,11 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
||||||
{
|
{
|
||||||
/* Check PACBTI security feature configuration before pushing the
|
/* Check PACBTI security feature configuration before pushing the
|
||||||
* CONTROL register's value on task's TCB. */
|
* CONTROL register's value on task's TCB. */
|
||||||
ulControl = prvConfigurePACBTI( pdFALSE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
ulControl = prvConfigurePACBTI( pdFALSE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
ulControl = vConfigurePACBTI( pdFALSE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1737,91 +1777,17 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configCHECK_HANDLER_INSTALLATION */
|
#endif /* configCHECK_HANDLER_INSTALLATION */
|
||||||
|
|
||||||
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
vPortConfigureInterruptPriorities();
|
||||||
{
|
|
||||||
volatile uint32_t ulImplementedPrioBits = 0;
|
|
||||||
volatile uint8_t ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
|
||||||
* functions can be called. ISR safe functions are those that end in
|
|
||||||
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
|
||||||
* ensure interrupt entry is as fast and simple as possible.
|
|
||||||
*
|
|
||||||
* First, determine the number of priority bits available. Write to all
|
|
||||||
* possible bits in the priority setting for SVCall. */
|
|
||||||
portNVIC_SHPR2_REG = 0xFF000000;
|
|
||||||
|
|
||||||
/* Read the value back to see how many bits stuck. */
|
|
||||||
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
|
||||||
|
|
||||||
/* Use the same mask on the maximum system call priority. */
|
|
||||||
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
|
||||||
|
|
||||||
/* Check that the maximum system call priority is nonzero after
|
|
||||||
* accounting for the number of priority bits supported by the
|
|
||||||
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
|
||||||
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
|
||||||
* cannot be masked using BASEPRI.
|
|
||||||
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
|
||||||
configASSERT( ucMaxSysCallPriority );
|
|
||||||
|
|
||||||
/* Check that the bits not implemented in hardware are zero in
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
|
||||||
|
|
||||||
/* Calculate the maximum acceptable priority group value for the number
|
|
||||||
* of bits read back. */
|
|
||||||
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
|
||||||
{
|
|
||||||
ulImplementedPrioBits++;
|
|
||||||
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ulImplementedPrioBits == 8 )
|
|
||||||
{
|
|
||||||
/* When the hardware implements 8 priority bits, there is no way for
|
|
||||||
* the software to configure PRIGROUP to not have sub-priorities. As
|
|
||||||
* a result, the least significant bit is always used for sub-priority
|
|
||||||
* and there are 128 preemption priorities and 2 sub-priorities.
|
|
||||||
*
|
|
||||||
* This may cause some confusion in some cases - for example, if
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
|
||||||
* priority interrupts will be masked in Critical Sections as those
|
|
||||||
* are at the same preemption priority. This may appear confusing as
|
|
||||||
* 4 is higher (numerically lower) priority than
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
|
||||||
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
|
||||||
* to 4, this confusion does not happen and the behaviour remains the same.
|
|
||||||
*
|
|
||||||
* The following assert ensures that the sub-priority bit in the
|
|
||||||
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
|
||||||
* confusion. */
|
|
||||||
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
|
||||||
ulMaxPRIGROUPValue = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift the priority group value back to its position within the AIRCR
|
|
||||||
* register. */
|
|
||||||
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
|
||||||
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
|
||||||
}
|
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
|
||||||
|
|
||||||
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
|
||||||
* the highest priority. */
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
|
||||||
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
|
||||||
portNVIC_SHPR2_REG = 0;
|
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
{
|
{
|
||||||
/* Set the CONTROL register value based on PACBTI security feature
|
/* Set the CONTROL register value based on PACBTI security feature
|
||||||
* configuration before starting the first task. */
|
* configuration before starting the first task. */
|
||||||
( void ) prvConfigurePACBTI( pdTRUE );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
( void ) prvConfigurePACBTI( pdTRUE );
|
||||||
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
|
( void ) vConfigurePACBTI( pdTRUE );
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
|
|
||||||
|
|
@ -1832,12 +1798,47 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
}
|
}
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
|
|
||||||
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
* here already. */
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
vPortSetupTimerInterrupt();
|
* here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count for all cores. */
|
||||||
|
for ( uint8_t ucCoreID = 0; ucCoreID < configNUMBER_OF_CORES; ucCoreID++ )
|
||||||
|
{
|
||||||
|
ulCriticalNestings[ ucCoreID ] = 0;
|
||||||
|
}
|
||||||
|
/* Signal that primary core has done all the necessary initialisations. */
|
||||||
|
ucPrimaryCoreInitDoneFlag = 1;
|
||||||
|
/* Wake up secondary cores */
|
||||||
|
BaseType_t xWakeResult = configWAKE_SECONDARY_CORES();
|
||||||
|
configASSERT( xWakeResult == pdTRUE );
|
||||||
|
|
||||||
/* Initialize the critical nesting count ready for the first task. */
|
/* Hold the primary core here until all the secondary cores are ready, this would be achieved only when
|
||||||
ulCriticalNesting = 0;
|
* 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. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
/* Initialize the critical nesting count ready for the first task. */
|
||||||
|
ulCriticalNesting = 0;
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -1854,7 +1855,11 @@ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
* functionality by defining configTASK_RETURN_ADDRESS. Call
|
||||||
* vTaskSwitchContext() so link time optimization does not remove the
|
* vTaskSwitchContext() so link time optimization does not remove the
|
||||||
* symbol. */
|
* symbol. */
|
||||||
vTaskSwitchContext();
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
vTaskSwitchContext( portGET_CORE_ID() );
|
||||||
|
#else
|
||||||
|
vTaskSwitchContext();
|
||||||
|
#endif
|
||||||
prvTaskExitError();
|
prvTaskExitError();
|
||||||
|
|
||||||
/* Should not get here. */
|
/* Should not get here. */
|
||||||
|
|
@ -1866,7 +1871,11 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
|
||||||
{
|
{
|
||||||
/* Not implemented in ports where there is nothing to return to.
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
* Artificially force an assert. */
|
* Artificially force an assert. */
|
||||||
configASSERT( ulCriticalNesting == 1000UL );
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
configASSERT( ulCriticalNesting == 1000UL );
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
configASSERT( ulCriticalNestings[ portGET_CORE_ID() ] == 1000UL );
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2149,6 +2158,90 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
|
||||||
|
{
|
||||||
|
#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulImplementedPrioBits = 0;
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
* functions can be called. ISR safe functions are those that end in
|
||||||
|
* "FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
* ensure interrupt entry is as fast and simple as possible.
|
||||||
|
*
|
||||||
|
* First, determine the number of priority bits available. Write to all
|
||||||
|
* possible bits in the priority setting for SVCall. */
|
||||||
|
portNVIC_SHPR2_REG = 0xFF000000;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Check that the maximum system call priority is nonzero after
|
||||||
|
* accounting for the number of priority bits supported by the
|
||||||
|
* hardware. A priority of 0 is invalid because setting the BASEPRI
|
||||||
|
* register to 0 unmasks all interrupts, and interrupts with priority 0
|
||||||
|
* cannot be masked using BASEPRI.
|
||||||
|
* See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( ucMaxSysCallPriority );
|
||||||
|
|
||||||
|
/* Check that the bits not implemented in hardware are zero in
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U );
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
* of bits read back. */
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulImplementedPrioBits++;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulImplementedPrioBits == 8 )
|
||||||
|
{
|
||||||
|
/* When the hardware implements 8 priority bits, there is no way for
|
||||||
|
* the software to configure PRIGROUP to not have sub-priorities. As
|
||||||
|
* a result, the least significant bit is always used for sub-priority
|
||||||
|
* and there are 128 preemption priorities and 2 sub-priorities.
|
||||||
|
*
|
||||||
|
* This may cause some confusion in some cases - for example, if
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4
|
||||||
|
* priority interrupts will be masked in Critical Sections as those
|
||||||
|
* are at the same preemption priority. This may appear confusing as
|
||||||
|
* 4 is higher (numerically lower) priority than
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not
|
||||||
|
* have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
* to 4, this confusion does not happen and the behaviour remains the same.
|
||||||
|
*
|
||||||
|
* The following assert ensures that the sub-priority bit in the
|
||||||
|
* configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned
|
||||||
|
* confusion. */
|
||||||
|
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U );
|
||||||
|
ulMaxPRIGROUPValue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
* register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
}
|
||||||
|
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
|
||||||
|
* the highest priority. */
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
portNVIC_SHPR2_REG = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) )
|
||||||
|
|
||||||
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle,
|
||||||
|
|
@ -2245,36 +2338,214 @@ BaseType_t xPortIsInsideInterrupt( void )
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
{
|
#else /* configNUMBER_OF_CORES > 1 */
|
||||||
uint32_t ulControl = 0x0;
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister )
|
||||||
|
#endif /* configNUMBER_OF_CORES */
|
||||||
/* Ensure that PACBTI is implemented. */
|
|
||||||
configASSERT( portID_ISAR5_REG != 0x0 );
|
|
||||||
|
|
||||||
/* Enable UsageFault exception. */
|
|
||||||
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
|
||||||
{
|
{
|
||||||
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
uint32_t ulControl = 0x0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ( configENABLE_BTI == 1 )
|
/* Ensure that PACBTI is implemented. */
|
||||||
{
|
configASSERT( portID_ISAR5_REG != 0x0 );
|
||||||
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( xWriteControlRegister == pdTRUE )
|
/* Enable UsageFault exception. */
|
||||||
{
|
portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT;
|
||||||
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ulControl;
|
#if ( configENABLE_PAC == 1 )
|
||||||
}
|
{
|
||||||
|
ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configENABLE_BTI == 1 )
|
||||||
|
{
|
||||||
|
ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( xWriteControlRegister == pdTRUE )
|
||||||
|
{
|
||||||
|
__asm volatile ( "msr control, %0" : : "r" ( ulControl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulControl;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
#endif /* configENABLE_PAC == 1 || configENABLE_BTI == 1 */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
|
||||||
|
/* Which core owns the lock? */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulOwnedByCore[ portMAX_CORE_COUNT ];
|
||||||
|
/* Lock count a core owns. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulRecursionCountByLock[ eLockCount ];
|
||||||
|
/* Index 0 is used for ISR lock and Index 1 is used for task lock. */
|
||||||
|
PRIVILEGED_DATA volatile uint32_t ulGateWord[ eLockCount ];
|
||||||
|
|
||||||
|
__attribute__((weak)) void vInterruptCore( uint8_t ucCoreID )
|
||||||
|
{
|
||||||
|
/* Default weak stub - platform specific implementation may override. */
|
||||||
|
( void ) ucCoreID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline void prvSpinUnlock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/* Conservative unlock: preserve original barriers for broad HW/FVP. */
|
||||||
|
__asm volatile (
|
||||||
|
"dmb sy \n"
|
||||||
|
"mov r1, #0 \n"
|
||||||
|
"str r1, [%0] \n"
|
||||||
|
"sev \n"
|
||||||
|
"dsb \n"
|
||||||
|
"isb \n"
|
||||||
|
:
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory", "r1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline uint32_t prvSpinTrylock( volatile uint32_t * ulLock )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Conservative ldrex/strex trylock:
|
||||||
|
* - Return 1 immediately if busy, clearing exclusive state (CLREX).
|
||||||
|
* - Retry strex only on spurious failure when observed free.
|
||||||
|
* - DMB on success to preserve expected acquire semantics.
|
||||||
|
*/
|
||||||
|
uint32_t ulVal;
|
||||||
|
uint32_t ulStatus;
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" ldrex %0, [%1] \n"
|
||||||
|
: "=r" ( ulVal )
|
||||||
|
: "r" ( ulLock )
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulVal != 0U )
|
||||||
|
{
|
||||||
|
__asm volatile ("clrex" ::: "memory");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
" strex %0, %2, [%1] \n"
|
||||||
|
: "=&r" ( ulStatus )
|
||||||
|
: "r" ( ulLock ), "r" (1U)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ulStatus != 0U )
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
__asm volatile ( "dmb" ::: "memory" );
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Read 32b value shared between cores. */
|
||||||
|
static inline uint32_t prvGet32( volatile uint32_t * x )
|
||||||
|
{
|
||||||
|
__asm( "dsb" );
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Write 32b value shared between cores. */
|
||||||
|
static inline void prvSet32( volatile uint32_t * x,
|
||||||
|
uint32_t value )
|
||||||
|
{
|
||||||
|
*x = value;
|
||||||
|
__asm( "dsb" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
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( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit )
|
||||||
|
{
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != portUINT32_MAX );
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) + 1 ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preload the gate word into the cache. */
|
||||||
|
uint32_t dummy = ulGateWord[ eLockNum ];
|
||||||
|
dummy++;
|
||||||
|
|
||||||
|
while( prvSpinTrylock( &ulGateWord[ eLockNum ] ) != 0 )
|
||||||
|
{
|
||||||
|
__asm volatile ( "wfe" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) == 0 );
|
||||||
|
|
||||||
|
/* Set lock count as 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], 1 );
|
||||||
|
/* Set ulOwnedByCore. */
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) | ulLockBit ) );
|
||||||
|
}
|
||||||
|
/* Lock release. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assert the lock is not free already. */
|
||||||
|
configASSERT( ( prvGet32( &ulOwnedByCore[ ucCoreID ] ) & ulLockBit ) != 0 );
|
||||||
|
configASSERT( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) != 0 );
|
||||||
|
|
||||||
|
/* Reduce ulRecursionCountByLock by 1. */
|
||||||
|
prvSet32( &ulRecursionCountByLock[ eLockNum ], ( prvGet32( &ulRecursionCountByLock[ eLockNum ] ) - 1 ) );
|
||||||
|
|
||||||
|
if( !prvGet32( &ulRecursionCountByLock[ eLockNum ] ) )
|
||||||
|
{
|
||||||
|
prvSet32( &ulOwnedByCore[ ucCoreID ], ( prvGet32( &ulOwnedByCore[ 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 )
|
||||||
|
{
|
||||||
|
return *(volatile uint8_t *)(configCORE_ID_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* if( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -41,7 +40,15 @@ files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler.
|
||||||
#define configUSE_MPU_WRAPPERS_V1 0
|
#define configUSE_MPU_WRAPPERS_V1 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configNUMBER_OF_CORES
|
||||||
|
#define configNUMBER_OF_CORES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
EXTERN pxCurrentTCB
|
EXTERN pxCurrentTCB
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
EXTERN pxCurrentTCBs
|
||||||
|
#endif
|
||||||
EXTERN vTaskSwitchContext
|
EXTERN vTaskSwitchContext
|
||||||
EXTERN vPortSVCHandler_C
|
EXTERN vPortSVCHandler_C
|
||||||
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
|
||||||
|
|
@ -169,8 +176,15 @@ vRestoreContextOfFirstTask:
|
||||||
#else /* configENABLE_MPU */
|
#else /* configENABLE_MPU */
|
||||||
|
|
||||||
vRestoreContextOfFirstTask:
|
vRestoreContextOfFirstTask:
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulFirstTaskLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
ldr r0, [r1] /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -193,6 +207,13 @@ vRestoreContextOfFirstTask:
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */
|
||||||
bx r2 /* Finally, branch to EXC_RETURN. */
|
bx r2 /* Finally, branch to EXC_RETURN. */
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulFirstTaskLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
@ -377,20 +398,37 @@ PendSV_Handler:
|
||||||
clrm {r1-r4} /* Clear r1-r4. */
|
clrm {r1-r4} /* Clear r1-r4. */
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
str r0, [r1] /* Save the new top of stack in TCB. */
|
str r0, [r1] /* Save the new top of stack in TCB. */
|
||||||
|
|
||||||
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
|
||||||
dsb
|
dsb
|
||||||
isb
|
isb
|
||||||
|
#if ( configNUMBER_OF_CORES > 1)
|
||||||
|
mov r0, r2 /* r0 = ucPortGetCoreID() */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
bl vTaskSwitchContext
|
bl vTaskSwitchContext
|
||||||
mov r0, #0 /* r0 = 0. */
|
mov r0, #0 /* r0 = 0. */
|
||||||
msr basepri, r0 /* Enable interrupts. */
|
msr basepri, r0 /* Enable interrupts. */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES == 1)
|
||||||
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
|
||||||
ldr r1, [r2] /* Read pxCurrentTCB. */
|
ldr r1, [r2] /* Read pxCurrentTCB. */
|
||||||
|
#else /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
|
ldr r1, =ulPendSVLiteralPool /* Get the location of the current TCB and the Id of the current core. */
|
||||||
|
ldmia r1!, {r2, r3}
|
||||||
|
ldr r2, [r2] /* r2 = Core Id */
|
||||||
|
ldr r1, [r3, r2, LSL #2] /* r1 = pxCurrentTCBs[CORE_ID] */
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES == 1) */
|
||||||
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
|
||||||
|
|
||||||
#if ( configENABLE_PAC == 1 )
|
#if ( configENABLE_PAC == 1 )
|
||||||
|
|
@ -413,6 +451,13 @@ PendSV_Handler:
|
||||||
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
msr psplim, r2 /* Restore the PSPLIM register value for the task. */
|
||||||
msr psp, r0 /* Remember the new top of stack for the task. */
|
msr psp, r0 /* Remember the new top of stack for the task. */
|
||||||
bx r3
|
bx r3
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
/* Align to 4 bytes in ROM/code area (2^2 alignment, 0 fill). */
|
||||||
|
ALIGNROM 2, 0
|
||||||
|
ulPendSVLiteralPool:
|
||||||
|
DC32 configCORE_ID_REGISTER /* CORE_ID_REGISTER */
|
||||||
|
DC32 pxCurrentTCBs
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
|
|
||||||
#endif /* configENABLE_MPU */
|
#endif /* configENABLE_MPU */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
* Copyright (c) 2025 Arm Technology (China) Co., Ltd.All Rights Reserved.
|
||||||
|
* Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
#define portHAS_ARMV8M_MAIN_EXTENSION 1
|
||||||
#define portARMV8M_MINOR_VERSION 1
|
#define portARMV8M_MINOR_VERSION 1
|
||||||
#define portDONT_DISCARD __root
|
#define portDONT_DISCARD __root
|
||||||
|
#define portVALIDATED_FOR_SMP 0
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* ARMv8-M common port configurations. */
|
/* ARMv8-M common port configurations. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
* Copyright 2024 Arm Limited and/or its affiliates
|
* Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||||
* <open-source-office@arm.com>
|
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
|
|
@ -31,6 +30,8 @@
|
||||||
#ifndef PORTMACROCOMMON_H
|
#ifndef PORTMACROCOMMON_H
|
||||||
#define PORTMACROCOMMON_H
|
#define PORTMACROCOMMON_H
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -59,6 +60,19 @@
|
||||||
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
|
||||||
#endif /* configENABLE_TRUSTZONE */
|
#endif /* configENABLE_TRUSTZONE */
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
#if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 )
|
||||||
|
#error "Multi-core SMP is currently only validated for Cortex-M33 non-TrustZone non-MPU port."
|
||||||
|
#endif /* if ( portVALIDATED_FOR_SMP != 1 ) || ( configENABLE_MPU == 1 ) || ( configENABLE_TRUSTZONE == 1 ) ) */
|
||||||
|
|
||||||
|
#ifndef configCORE_ID_REGISTER
|
||||||
|
#error "configCORE_ID_REGISTER must be defined to the address of the register used to identify the core executing the code."
|
||||||
|
#endif /* ifndef configCORE_ID_REGISTER */
|
||||||
|
|
||||||
|
#ifndef configWAKE_SECONDARY_CORES
|
||||||
|
#error "configWAKE_SECONDARY_CORES must be defined to a function that wakes the secondary cores."
|
||||||
|
#endif /* ifndef configWAKE_SECONDARY_CORES */
|
||||||
|
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +153,11 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
void vApplicationGenerateTaskRandomPacKey( uint32_t * pulTaskPacKey );
|
||||||
|
|
||||||
#endif /* configENABLE_PAC */
|
#endif /* configENABLE_PAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures interrupt priorities.
|
||||||
|
*/
|
||||||
|
void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -428,10 +447,26 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/**
|
/**
|
||||||
* @brief Critical section management.
|
* @brief Critical section management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x )
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
|
||||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
|
||||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
#if ( configNUMBER_OF_CORES == 1 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#else /* ( configNUMBER_OF_CORES == 1 ) */
|
||||||
|
extern void vTaskEnterCritical( void );
|
||||||
|
extern void vTaskExitCritical( void );
|
||||||
|
extern UBaseType_t vTaskEnterCriticalFromISR( void );
|
||||||
|
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||||
|
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
|
||||||
|
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
|
||||||
|
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -526,7 +561,7 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
* based on whether or not Mainline extension is implemented. */
|
* based on whether or not Mainline extension is implemented. */
|
||||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
|
#if ( ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) && ( configNUMBER_OF_CORES == 1 ) )
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
#else
|
#else
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
@ -573,6 +608,44 @@ extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) P
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#if ( configNUMBER_OF_CORES > 1 )
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eIsrLock = 0,
|
||||||
|
eTaskLock,
|
||||||
|
eLockCount
|
||||||
|
} ePortRTOSLock;
|
||||||
|
|
||||||
|
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
|
||||||
|
extern void vPortRecursiveLock( uint8_t ucCoreID,
|
||||||
|
ePortRTOSLock eLockNum,
|
||||||
|
BaseType_t uxAcquire );
|
||||||
|
extern uint8_t ucPortGetCoreID( void );
|
||||||
|
extern void vInterruptCore( uint8_t ucCoreID );
|
||||||
|
|
||||||
|
#define portGET_CORE_ID() ucPortGetCoreID()
|
||||||
|
|
||||||
|
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] )
|
||||||
|
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
|
||||||
|
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]++ )
|
||||||
|
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( uint8_t ) xCoreID ]-- )
|
||||||
|
|
||||||
|
#define portMAX_CORE_COUNT ( configNUMBER_OF_CORES )
|
||||||
|
|
||||||
|
#define portYIELD_CORE( xCoreID ) vInterruptCore( xCoreID )
|
||||||
|
|
||||||
|
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
|
||||||
|
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
|
||||||
|
|
||||||
|
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
|
||||||
|
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
|
||||||
|
|
||||||
|
#if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) )
|
||||||
|
uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister );
|
||||||
|
#endif /* ( configENABLE_PAC == 1 || configENABLE_BTI == 1 ) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue