Release v11.3.1_20261016
diff --git a/README.md b/README.md index 09619a1..e1fcd79 100644 --- a/README.md +++ b/README.md
@@ -1,6 +1,6 @@ # Middleware FreeRTOS MCU Component - + ## Overview
diff --git a/Source/CMSIS_RTOS_V2/cmsis_os2.c b/Source/CMSIS_RTOS_V2/cmsis_os2.c index 5469c12..8083c7f 100644 --- a/Source/CMSIS_RTOS_V2/cmsis_os2.c +++ b/Source/CMSIS_RTOS_V2/cmsis_os2.c
@@ -1,5 +1,5 @@ /* -------------------------------------------------------------------------- - * Copyright (c) 2013-2024 Arm Limited. All rights reserved. + * Copyright 2013-2026 Arm Limited and/or its affiliates. * * SPDX-License-Identifier: Apache-2.0 * @@ -84,8 +84,8 @@ #define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) /* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */ -#define KERNEL_VERSION (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) | \ - ((uint32_t)tskKERNEL_VERSION_MINOR * 10000UL) | \ +#define KERNEL_VERSION (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) + \ + ((uint32_t)tskKERNEL_VERSION_MINOR * 10000UL) + \ ((uint32_t)tskKERNEL_VERSION_BUILD * 1UL)) #define KERNEL_ID ("FreeRTOS " tskKERNEL_VERSION_NUMBER) @@ -127,7 +127,7 @@ HeapRegion_t array. */ #define HEAP_5_REGION_SETUP 1 - + #ifndef configHEAP_5_REGIONS #define configHEAP_5_REGIONS xHeapRegions @@ -176,7 +176,6 @@ #endif #endif /* SysTick */ - /* Determine if CPU executes from interrupt context or if interrupts are masked. */ @@ -580,9 +579,9 @@ mem = -1; if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } + /* Take the name from attributes */ + name = attr->name; + if (attr->priority != osPriorityNone) { prio = (UBaseType_t)attr->priority; } @@ -592,6 +591,11 @@ return (NULL); } + if ((attr->attr_bits & osThreadPrivileged) == osThreadPrivileged) { + /* Set privilege bit to create a privileged task */ + prio |= portPRIVILEGE_BIT; + } + if (attr->stack_size > 0U) { /* In FreeRTOS stack is not in bytes, but in sizeof(StackType_t) which is 4 on ARM ports. */ /* Stack size should be therefore 4 byte aligned in order to avoid division caused side effects */ @@ -883,9 +887,10 @@ Terminate execution of a thread. */ osStatus_t osThreadTerminate (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; osStatus_t stat; + #ifndef USE_FreeRTOS_HEAP_1 + TaskHandle_t hTask = (TaskHandle_t)thread_id; eTaskState tstate; if (IRQ_Context() != 0U) { @@ -905,6 +910,7 @@ } } #else + (void)thread_id; stat = osError; #endif @@ -1048,8 +1054,7 @@ Clear the specified Thread Flags of current running thread. */ uint32_t osThreadFlagsClear (uint32_t flags) { - TaskHandle_t hTask; - uint32_t rflags, cflags; + uint32_t rflags; if (IRQ_Context() != 0U) { rflags = (uint32_t)osErrorISR; @@ -1058,19 +1063,7 @@ rflags = (uint32_t)osErrorParameter; } else { - hTask = xTaskGetCurrentTaskHandle(); - - if (xTaskNotifyAndQuery (hTask, 0, eNoAction, &cflags) == pdPASS) { - rflags = cflags; - cflags &= ~flags; - - if (xTaskNotify (hTask, cflags, eSetValueWithOverwrite) != pdPASS) { - rflags = (uint32_t)osError; - } - } - else { - rflags = (uint32_t)osError; - } + rflags = ulTaskNotifyValueClear(NULL, flags); } /* Return flags before clearing */ @@ -1326,9 +1319,8 @@ name = NULL; if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } + /* Take the name from attributes */ + name = attr->name; if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTimer_t))) { /* The memory for control block is provided, use static object */ @@ -1477,12 +1469,13 @@ Delete a timer. */ osStatus_t osTimerDelete (osTimerId_t timer_id) { - TimerHandle_t hTimer = (TimerHandle_t)timer_id; osStatus_t stat; + #ifndef USE_FreeRTOS_HEAP_1 -#if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + TimerHandle_t hTimer = (TimerHandle_t)timer_id; + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) TimerCallback_t *callb; -#endif + #endif if (IRQ_Context() != 0U) { stat = osErrorISR; @@ -1511,6 +1504,7 @@ } } #else + (void)timer_id; stat = osError; #endif @@ -1742,10 +1736,11 @@ Delete an Event Flags object. */ osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; osStatus_t stat; #ifndef USE_FreeRTOS_HEAP_1 + EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; + if (IRQ_Context() != 0U) { stat = osErrorISR; } @@ -1757,6 +1752,7 @@ vEventGroupDelete (hEventGroup); } #else + (void)ef_id; stat = osError; #endif @@ -1973,6 +1969,7 @@ */ osStatus_t osMutexDelete (osMutexId_t mutex_id) { osStatus_t stat; + #ifndef USE_FreeRTOS_HEAP_1 SemaphoreHandle_t hMutex; @@ -1992,6 +1989,7 @@ vSemaphoreDelete (hMutex); } #else + (void)mutex_id; stat = osError; #endif @@ -2176,10 +2174,11 @@ Delete a Semaphore object. */ osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; osStatus_t stat; #ifndef USE_FreeRTOS_HEAP_1 + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; + if (IRQ_Context() != 0U) { stat = osErrorISR; } @@ -2195,6 +2194,7 @@ vSemaphoreDelete (hSemaphore); } #else + (void)semaphore_id; stat = osError; #endif @@ -2432,7 +2432,7 @@ else if (IRQ_Context() != 0U) { isrm = taskENTER_CRITICAL_FROM_ISR(); - space = uxQueueGetQueueLength (hQueue) - uxQueueMessagesWaiting (hQueue); + space = uxQueueGetQueueLength (hQueue) - uxQueueMessagesWaitingFromISR (hQueue); taskEXIT_CRITICAL_FROM_ISR(isrm); } @@ -2470,10 +2470,11 @@ Delete a Message Queue object. */ osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) { - QueueHandle_t hQueue = (QueueHandle_t)mq_id; osStatus_t stat; #ifndef USE_FreeRTOS_HEAP_1 + QueueHandle_t hQueue = (QueueHandle_t)mq_id; + if (IRQ_Context() != 0U) { stat = osErrorISR; } @@ -2489,6 +2490,7 @@ vQueueDelete (hQueue); } #else + (void)mq_id; stat = osError; #endif @@ -2529,9 +2531,8 @@ mem_mp = -1; if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } + /* Take the name from attributes */ + name = attr->name; if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(MemPool_t))) { /* Static control block is provided */ @@ -2568,10 +2569,14 @@ if (mem_cb == 0) { mp = pvPortMalloc (sizeof(MemPool_t)); } else { - mp = attr->cb_mem; + if(mem_cb == 1) { + mp = attr->cb_mem; + } } if (mp != NULL) { + mp->mem_arr = NULL; + /* Create a semaphore (max count == initial count == block_count) */ #if (configSUPPORT_STATIC_ALLOCATION == 1) mp->sem = xSemaphoreCreateCountingStatic (block_count, block_count, &mp->mem_sem); @@ -2586,7 +2591,9 @@ if (mem_mp == 0) { mp->mem_arr = pvPortMalloc (sz); } else { - mp->mem_arr = attr->mp_mem; + if(mem_mp == 1) { + mp->mem_arr = attr->mp_mem; + } } } }
diff --git a/Source/History.txt b/Source/History.txt index 7df76e1..7baa62a 100644 --- a/Source/History.txt +++ b/Source/History.txt
@@ -1,5 +1,255 @@ Documentation and download available at https://www.FreeRTOS.org/ +Changes between FreeRTOS V11.3.0 and FreeRTOS V11.3.1 released August 2026 + + + Add Symmetric Multiprocessing (SMP) support to the Armv8-M ports for the + GCC, ArmClang and IAR toolchains. This adds per core critical nesting + state, spinlocks, inter-core yield and wakeup using SEV/WFE, primary and + secondary core bring up synchronization, and a core safe PendSV context + switch. Single core builds are unchanged. We thank @AhmedIsmail02 for + their contribution. + + Add new xTaskPeriodicDelay API for periodic tasks. It supersedes + xTaskDelayUntil by preventing run away of pxPreviousWakeTime, catching up + skipped periods immediately while returning the number of periods skipped, + and returning 0 when not enough ticks have elapsed. We thank @ntd for + their contribution. + + Add uxTaskCallForEachTask API, which invokes a caller supplied callback + for each task in the system, and refactor uxTaskGetSystemState to use it. + We thank @DRNadler for their contribution. + + Add configIDLE_AFFINITY configuration option, which pins each Idle task to + its corresponding core in SMP systems. It defaults to 0, which allows the + scheduler to run Idle tasks on any available core. We thank @rus084 for + their contribution. + + Add validation to SecureContext_AllocateContext in the ARMv8-M secure side + ports to ensure that the requested secure stack size plus the stack seal + size does not overflow before allocating. We thank Jordan Mecom (Block, + Inc.) for reporting this issue. + + Add assertions to vQueueDelete to check that no tasks are blocked on the + queue being deleted. + + Add a link to the FreeRTOS Kernel threat model in SECURITY.md. + + Add documentation clarifying that the MemoryRegion_t ulParameters macros + are port specific, so applications must use the tskMPU_REGION_* or + portMPU_REGION_* values that match their MPU port. We thank @Old-Ding for + their contribution. + + Add a comment documenting that a privileged task must revoke access + permissions before deleting a kernel object when using Access Control + Lists. + + Update the ARM_CRx_No_GIC port to declare vPortYield as a weak symbol so + that devices with a dedicated software interrupt register can substitute + their own yield trigger. The default behavior is unchanged. We thank + @maximdeclercq for their contribution. + + Update the FreeRTOSConfig.h template to use a 32-bit tick type, which + avoids compiler warnings on Windows where a 64-bit tick resolves to + unsigned long long. + + Update the deprecated CMake configuration warning to use INTERFACE rather + than PUBLIC for the freertos_config interface library. We thank @Isla-jq + for their contribution. + + Fix vPortFreeSecureContext in the ARMv8-M ports to read xSecureContext at + the correct offset. When the MPU is enabled, the first item in the TCB is + the stored context location rather than the top of stack, so + xSecureContext is located at a negative offset from that position. + + Fix SecureContext_AllocateContext in the ARMv8-M secure side ports to + reject a secure stack size smaller than the stack seal size. + + Fix SecureContext_FreeContext in the ARMv8-M secure side ports to refuse + to free the secure context that is currently loaded, as indicated by + PSPLIM. Freeing it left the running task referencing freed secure memory. + The task handle supplied by the non-secure side is untrusted, so it is + now used only as an additional ownership check. + + Fix the ARMv8-M ports to service the portSVC_START_SCHEDULER and + portSVC_FREE_SECURE_CONTEXT supervisor calls only when they are raised + from privileged code. When the MPU is enabled, both requests are now + ignored unless the calling program counter lies within the privileged + functions section. + + Fix a type confusion in xQueueAddToSet by verifying that the object + passed as the queue set really is a queue set, that is, that its item + size is sizeof( Queue_t * ). Passing an ordinary queue now returns + pdFAIL rather than allowing prvNotifyQueueSetContainer to copy item size + bytes from a single pointer on the stack. + + Fix xTimerGenericCommandFromTask to validate the lower bound of + xCommandID in addition to the existing upper bound, so that only the + valid task command range from tmrCOMMAND_START_DONT_TRACE to + tmrCOMMAND_DELETE is accepted. Rejected commands return pdFAIL, and + behavior for valid commands and for xTimerGenericCommandFromISR is + unchanged. + + Fix a kernel object pool entry leak by adding an MPU wrapper for the + xTimerDelete API, so that the pool index is freed when a timer is deleted + with MPU wrappers version 2. + + Fix the MPU wrapper macro mapping for the ARMv8-M ports. + + Fix silently failing critical sections in unprivileged tasks by + disallowing configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS with MPU wrappers + version 2 in the ARMv7-M MPU ports. The option now defaults to 0 under + version 2, and explicitly setting it to 1 raises a compile time error. + Behavior with MPU wrappers version 1 is unchanged. + + Fix a time of check to time of use race condition in vTaskListTasks, where + reading the volatile task count twice allowed a task to be created between + the reads, resulting in an undersized allocation and a possible buffer + overflow in uxTaskGetSystemState. We thank @srpatcha for their + contribution. + + Fix a spurious heap_5 assertion when configENABLE_HEAP_PROTECTOR is 1 and + an allocation cannot be satisfied. The free block search reaching the end + marker is a normal out of memory condition, so pvPortMalloc now returns + NULL and invokes the malloc failed hook instead of asserting. + + Fix batching stream buffers to unblock a receiver only after the buffered + byte count exceeds, rather than reaches, the trigger level. Previously a + receiver could be woken early and xStreamBufferReceive could return 0 + bytes. Stream buffer and message buffer semantics are unchanged. We thank + @officialasishkumar for their contribution. + + Fix MISRA C 2012 Rule 20.4 violation by replacing `#define static` with a + STATIC macro, which also keeps the static variables in + vApplicationGetIdleTaskMemory and vApplicationGetPassiveIdleTaskMemory + static when portREMOVE_STATIC_QUALIFIER is defined. We thank @elsonwei for + their contribution. + + Fix undefined behavior in the MSVC-MingW port caused by left shifting a + signed int by 31 or more bits. + + Fix a duplicate Doxygen \defgroup identifier by giving + uxTaskBasePriorityGet its own group instead of reusing the + uxTaskPriorityGet group. + + Fix the incorrect #endif comment after vPortSetupTimerInterrupt in the GCC + and IAR RISC-V ports, which duplicated configMTIME_BASE_ADDRESS and + omitted configMTIMECMP_BASE_ADDRESS. We thank @cuiweixie for their + contribution. + + Fix incorrect #endif comments in croutine.c and queue.c, which reversed + the configUSE_CO_ROUTINES condition and named the wrong configuration + option for configSUPPORT_DYNAMIC_ALLOCATION. We thank @Zepp-Hanzj for + their contribution. + + Fix the configLIST_VOLATILE #endif comment and the documented parameter + names for uxListRemove in include/list.h. We thank @rakeshr-source for + their contribution. + + Fix the type and timeout values used in the xStreamBufferSend and + xMessageBufferSend documentation examples. We thank @Isla-jq for their + contribution. + + Fix copy and paste comment typos in xTaskGetApplicationTaskTag and + xTaskGetApplicationTaskTagFromISR, and a typo in the + xTaskGenericNotifyWait comment. We thank @wanghengZzz for their + contributions. + + Fix comment typos in the queue.h, list.h and task.h documentation, + including the xQueueReceiveFromISR and xQueueGenericSend examples, the + listGET_ITEM_VALUE_OF_HEAD_ENTRY \page tag, and the uxIndexToCLear typo. + We thank @zepp-chen for their contribution. + + Fix the FreeRTOSConfig.h template path referenced in README.md. We thank + @IClementI for their contribution. + + Fix the missing V prefix in the release_tag and namespace-prefix inputs of + the auto release workflow. + + Fix long path failures in the Windows kernel demo builds by enabling + Windows long path support in CI. + + Remove an unnecessary const variable from the GCC and IAR RISC-V ports. We + thank @IClementI for their contribution. + +Changes between FreeRTOS V11.2.0 and FreeRTOS V11.3.0 released March 2026 + + + Correct minor mistakes in code comments in event_groups.c, include/queue.h, + and include/task.h. We thank @wirelinker for their contribution. + + Add Arm China STAR-MC3 port support. We thank @cpussw01 for their + contribution. + + Add Memory Protection Unit (MPU) support to the ARM Cortex-R82 port. We + thank @AhmedIsmail02 for their contribution. + + Add ARM Cortex-M52 port support for GCC and IAR compilers. We thank + @Armchina_JidongMei for their contribution. + + Add ARM Cortex-R82 non-MPU port for ARMv8-R AArch64 with SMP support. We + thank @AhmedIsmail02 for their contribution. + + Add Floating Point Unit (FPU) context save support to the RISC-V port. + We thank @cubidesj for their contribution. + + Add Vector context save support to the RISC-V port. We thank @cubidesj + for their contribution. + + Add xPortIsInsideInterrupt API to the RP2040 port to match other ARM + ports. We thank @graham-sanderson for their contribution. + + Add catch up behavior documentation to xTaskDelayUntil API to explain + frequency breaks when catching up for past events. + + Add asserts to check for stack overflow at task creation time. + + Add assert to check for overflow in xStreamBufferSendFromISR API. + + Add assert to check for overflow of recursive mutex counter. We thank + @InnerSteff for their contribution. + + Add CFI frame unwind information in portable/IAR/RXv2/port_asm.s to + enable debugger callstack display beyond __interrupt_27. We thank + @bernd-edlinger for their contribution. + + Update xTaskDelayUntil to be the preferred delay function in the + FreeRTOSConfig.h template. + + Update RISC-V port to use saved mstatus for FPU/VPU state determination + instead of re-reading after writes, addressing specification-compliant + implementations where FS field may change to Dirty. + + Update RISC-V port to refine vector context layout on stack for proper + register ordering. We thank @Saiiijchan for their contribution. + + Update RISC-V port to refine FPU register context offset calculation. We + thank @Saiiijchan for their contribution. + + Update RISC-V port to use UBaseType_t for ullMachineTimerCompareRegisterBase + to resolve warnings on 32-bit platforms. + + Update FreeRTOS MPU to remove the assertion and runtime check enforcing + matching between configTOTAL_MPU_REGIONS and physical MPU regions, + allowing applications to manage a subset of available regions. We thank + @ErickReyesR for their contribution. + + Update ARM_CRx_No_GIC port to set Data endianness bit in SPSR register + for big-endian compilation. We thank @maximdeclercq00 for their + contribution. + + Update Win32 port to guard timeapi.h include for MinGW compatibility and + add compiler-specific headers for cross-compiler support. We thank + @nordync for their contribution. + + Update Win32 port to move Windows headers to port.c to prevent inclusion + of windows.h in all header files and avoid macro conflicts. We thank + @creiter64 for their contribution. + + Update POSIX port to delete thread key on process exit instead of in + xPortStartScheduler to ensure proper cleanup of thread-specific memory. + + Update POSIX port to fix race condition in vPortEndScheduler by moving + scheduler thread signal after FreeRTOS thread check. We thank + @arctic-alpaca for their contribution. + + Update RP2040 port to fix use of deprecated volatile semantics for C++20 + compatibility. We thank @mathiasgredal for their contribution. + + Update RP2040 port to propagate PICO_SDK_VERSION_* to parent scope in + CMake. We thank @shengtai25 for their contribution. + + Update RP2040 port to remove unused code and preprocessor directives. We + thank @pascalr for their contribution. + + Update RL78 port to fix incorrect register image for pvParameters in FAR + data model for IAR compiler. We thank @sauleThsQuin for their + contribution. + + Update RL78 port to fix compilation failure on portasm.s file due to + indentation on ASM macro. We thank @5iBri for their contribution. + + Update ARM_CRx_MPU port to add LLVM assembler compatibility by + explicitly specifying section flags. We thank @malsyned for their + contribution. + + Update Cortex-M ports to rename ulStackFrameSize to + ulHardwareSavedExceptionFrameSize for improved readability. We thank + @AhmedIsmail02 for their contribution. + + Update MPLAB PIC32MZ-EF port to add assert to catch register overflow. + We thank @mrluzeiro for their contribution. + + Update comments related to taskYIELD in queue.h. We thank @Saiiijchan + for their contribution. + + Fix priority disinheritance in vTaskPriorityDisinheritAfterTimeout to + reset the correct priority when the task disinheriting timeout was the + only task at that priority. + + Fix event groups to remove direct mapping of xEventGroupClearBitsFromISR + and xEventGroupSetBitsFromISR to xTimerPendFunctionCallFromISR, + resolving redefinition warnings. We thank @AhmedIsmail02 for their + contribution. + + Fix datatype of queue item length macros from uint8_t to UBaseType_t to + match API parameter types. + + Fix possible NULL pointer dereference after configASSERT() calls in + queue.c and stream_buffer.c. We thank @Florian.LaRoche for their + contribution. + + Fix Win32 port to prevent SetWaitableTimer() call from being ignored + when configASSERT expands to nothing. We thank @kim-schwaner for their + contribution. + + Fix compiler warnings from gcc -Wconversion. We thank @Florian.LaRoche + for their contribution. + + Fix compiler warning about gcc -Wwrite-strings in POSIX port. We thank + @Florian.LaRoche for their contribution. + + Fix set but unused variable warning in pxPortInitialiseStack. We thank + @razrbro for their contribution. + + Fix missing include to resolve compile error. We thank @mike919192 for + their contribution. + + Fix missing cast to BaseType_t. + + Fix cast in stack allocation for task creation for negative + portSTACK_GROWTH. We thank @sidharthseela for their contribution. + + Fix missing macro guards in task.h to prevent unintended API access. We + thank @SoniHarsh1 for their contribution. + + Fix CMake build for GCC_ARM_CRx_MPU by adding to mpu_wrappers patterns. + We thank @malsyned for their contribution. + + Fix initialization of size_t-type variable by changing macro from + portMAX_DELAY to SIZE_MAX. We thank @duyicheng741 for their + contribution. + + Define configENABLE_PAC and configENABLE_BTI before including portable.h + to prevent "used before definition" warnings. + + Remove stray semicolon from gcc-ARM_CRx_MPU port.c. We thank + @Florian.LaRoche for their contribution. + Changes between FreeRTOS V11.1.0 and FreeRTOS V11.2.0 released March 04, 2025 + Add CC-RH port for Renesas F1Kx devices. We thank @TrongNguyenR for their
diff --git a/Source/README.md b/Source/README.md index a6d383a..fabe522 100644 --- a/Source/README.md +++ b/Source/README.md
@@ -1,5 +1,5 @@ [](https://github.com/FreeRTOS/FreeRTOS-Kernel/actions/workflows/unit-tests.yml?query=branch%3Amain+event%3Apush+workflow%3A%22CMock+Unit+Tests%22++) -[](https://codecov.io/gh/FreeRTOS/FreeRTOS-Kernel) +[](https://codecov.io/gh/FreeRTOS/FreeRTOS-Kernel) ## Getting started @@ -130,7 +130,7 @@ - The ```./include``` directory contains the real time kernel header files. -- The ```./template_configuration``` directory contains a sample `FreeRTOSConfig.h` to help jumpstart a new project. +- The ```./examples/template_configuration``` directory contains a sample `FreeRTOSConfig.h` to help jumpstart a new project. See the [FreeRTOSConfig.h](examples/template_configuration/FreeRTOSConfig.h) file for instructions. ### Code Formatting
diff --git a/Source/croutine.c b/Source/croutine.c index 99aa0dc..397c052 100644 --- a/Source/croutine.c +++ b/Source/croutine.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -38,24 +38,26 @@ * than file scope. */ #ifdef portREMOVE_STATIC_QUALIFIER - #define static + #define STATIC + #else + #define STATIC static #endif /* Lists for ready and blocked co-routines. --------------------*/ - static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /**< Prioritised ready co-routines. */ - static List_t xDelayedCoRoutineList1; /**< Delayed co-routines. */ - static List_t xDelayedCoRoutineList2; /**< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ - static List_t * pxDelayedCoRoutineList = NULL; /**< Points to the delayed co-routine list currently being used. */ - static List_t * pxOverflowDelayedCoRoutineList = NULL; /**< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ - static List_t xPendingReadyCoRoutineList; /**< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ + STATIC List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /**< Prioritised ready co-routines. */ + STATIC List_t xDelayedCoRoutineList1; /**< Delayed co-routines. */ + STATIC List_t xDelayedCoRoutineList2; /**< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ + STATIC List_t * pxDelayedCoRoutineList = NULL; /**< Points to the delayed co-routine list currently being used. */ + STATIC List_t * pxOverflowDelayedCoRoutineList = NULL; /**< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ + STATIC List_t xPendingReadyCoRoutineList; /**< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ /* Other file private variables. --------------------------------*/ CRCB_t * pxCurrentCoRoutine = NULL; - static UBaseType_t uxTopCoRoutineReadyPriority = ( UBaseType_t ) 0U; - static TickType_t xCoRoutineTickCount = ( TickType_t ) 0U; - static TickType_t xLastTickCount = ( TickType_t ) 0U; - static TickType_t xPassedTicks = ( TickType_t ) 0U; + STATIC UBaseType_t uxTopCoRoutineReadyPriority = ( UBaseType_t ) 0U; + STATIC TickType_t xCoRoutineTickCount = ( TickType_t ) 0U; + STATIC TickType_t xLastTickCount = ( TickType_t ) 0U; + STATIC TickType_t xPassedTicks = ( TickType_t ) 0U; /* The initial state of the co-routine when it is created. */ #define corINITIAL_STATE ( 0 ) @@ -80,7 +82,7 @@ * Utility to ready all the lists used by the scheduler. This is called * automatically upon the creation of the first co-routine. */ - static void prvInitialiseCoRoutineLists( void ); + STATIC void prvInitialiseCoRoutineLists( void ); /* * Co-routines that are readied by an interrupt cannot be placed directly into @@ -88,7 +90,7 @@ * in the pending ready list in order that they can later be moved to the ready * list by the co-routine scheduler. */ - static void prvCheckPendingReadyList( void ); + STATIC void prvCheckPendingReadyList( void ); /* * Macro that looks at the list of co-routines that are currently delayed to @@ -98,7 +100,7 @@ * meaning once one co-routine has been found whose timer has not expired * we need not look any further down the list. */ - static void prvCheckDelayedList( void ); + STATIC void prvCheckDelayedList( void ); /*-----------------------------------------------------------*/ @@ -212,7 +214,7 @@ } /*-----------------------------------------------------------*/ - static void prvCheckPendingReadyList( void ) + STATIC void prvCheckPendingReadyList( void ) { /* Are there any co-routines waiting to get moved to the ready list? These * are co-routines that have been readied by an ISR. The ISR cannot access @@ -235,7 +237,7 @@ } /*-----------------------------------------------------------*/ - static void prvCheckDelayedList( void ) + STATIC void prvCheckDelayedList( void ) { CRCB_t * pxCRCB; @@ -333,7 +335,7 @@ } /*-----------------------------------------------------------*/ - static void prvInitialiseCoRoutineLists( void ) + STATIC void prvInitialiseCoRoutineLists( void ) { UBaseType_t uxPriority; @@ -402,4 +404,4 @@ } /*-----------------------------------------------------------*/ -#endif /* configUSE_CO_ROUTINES == 0 */ +#endif /* configUSE_CO_ROUTINES != 0 */
diff --git a/Source/event_groups.c b/Source/event_groups.c index 09f2ec0..4714467 100644 --- a/Source/event_groups.c +++ b/Source/event_groups.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -72,7 +72,7 @@ * The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is * pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor * are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the - * wait condition is met if any of the bits set in uxBitsToWait for are also set + * wait condition is met if any of the bits set in uxBitsToWaitFor are also set * in uxCurrentEventBits. */ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, @@ -501,7 +501,7 @@ } /*-----------------------------------------------------------*/ - #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + #if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) @@ -511,14 +511,14 @@ traceENTER_xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ); traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ); - xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); + xReturn = xTimerPendFunctionCallFromISR( &vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); traceRETURN_xEventGroupClearBitsFromISR( xReturn ); return xReturn; } - #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ + #endif /* if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ /*-----------------------------------------------------------*/ EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) @@ -812,7 +812,7 @@ } /*-----------------------------------------------------------*/ - #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + #if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, @@ -823,14 +823,14 @@ traceENTER_xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ); traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ); - xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); + xReturn = xTimerPendFunctionCallFromISR( &vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); traceRETURN_xEventGroupSetBitsFromISR( xReturn ); return xReturn; } - #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ + #endif /* if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 )
diff --git a/Source/include/FreeRTOS.h b/Source/include/FreeRTOS.h index 75459a9..1a7e6e7 100644 --- a/Source/include/FreeRTOS.h +++ b/Source/include/FreeRTOS.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -101,6 +101,16 @@ #define configASSERT_DEFINED 1 #endif +/* Set configENABLE_PAC and/or configENABLE_BTI to 1 to enable PAC and/or BTI + * support and 0 to disable them. These are currently used in ARMv8.1-M ports. */ +#ifndef configENABLE_PAC + #define configENABLE_PAC 0 +#endif + +#ifndef configENABLE_BTI + #define configENABLE_BTI 0 +#endif + /* Basic FreeRTOS definitions. */ #include "projdefs.h" @@ -367,6 +377,10 @@ #define configIDLE_SHOULD_YIELD 1 #endif +#ifndef configIDLE_AFFINITY + #define configIDLE_AFFINITY 0 +#endif + #if configMAX_TASK_NAME_LEN < 1 #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h #endif @@ -1756,6 +1770,14 @@ #define traceRETURN_vTaskDelete() #endif +#ifndef traceENTER_xTaskPeriodicDelay + #define traceENTER_xTaskPeriodicDelay( pxPreviousWakeTime, xTimeIncrement ) +#endif + +#ifndef traceRETURN_xTaskPeriodicDelay + #define traceRETURN_xTaskPeriodicDelay( xIncrements ) +#endif + #ifndef traceENTER_xTaskDelayUntil #define traceENTER_xTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ) #endif @@ -3040,16 +3062,6 @@ #define configCONTROL_INFINITE_LOOP() #endif -/* Set configENABLE_PAC and/or configENABLE_BTI to 1 to enable PAC and/or BTI - * support and 0 to disable them. These are currently used in ARMv8.1-M ports. */ -#ifndef configENABLE_PAC - #define configENABLE_PAC 0 -#endif - -#ifndef configENABLE_BTI - #define configENABLE_BTI 0 -#endif - /* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using * dynamically allocated RAM, in which case when any task is deleted it is known * that both the task's stack and TCB need to be freed. Sometimes the
diff --git a/Source/include/FreeRTOSConfig_template.h b/Source/include/FreeRTOSConfig_template.h index 4df0001..88efedd 100644 --- a/Source/include/FreeRTOSConfig_template.h +++ b/Source/include/FreeRTOSConfig_template.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -136,7 +136,7 @@ * * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_64_BITS causes * TickType_t to be defined (typedef'ed) as an unsigned 64-bit type. */ -#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_64_BITS +#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_32_BITS /* Set configIDLE_SHOULD_YIELD to 1 to have the Idle task yield to an * application task if there is an Idle priority (priority 0) application task @@ -415,6 +415,8 @@ * number of the failing assert (for example, "vAssertCalled( __FILE__, __LINE__ * )" or it can simple disable interrupts and sit in a loop to halt all * execution on the failing line for viewing in a debugger. */ + +/* *INDENT-OFF* */ #define configASSERT( x ) \ if( ( x ) == 0 ) \ { \ @@ -422,6 +424,7 @@ for( ; ; ) \ ; \ } +/* *INDENT-ON* */ /******************************************************************************/ /* FreeRTOS MPU specific definitions. *****************************************/ @@ -555,6 +558,13 @@ * tskNO_AFFINITY if left undefined. */ #define configTIMER_SERVICE_TASK_CORE_AFFINITY tskNO_AFFINITY +/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set + * configIDLE_AFFINITY to 1 to pin each Idle task to its corresponding + * core. When set to 1, Idle task N will only run on core N, using an affinity + * mask of (1 << N). Set to 0 to allow the scheduler to run Idle tasks on any + * available core. Defaults to 0 if left undefined. */ +#define configIDLE_AFFINITY 0 + /******************************************************************************/ /* ARMv8-M secure side port related definitions. ******************************/ /******************************************************************************/ @@ -567,7 +577,7 @@ /* Defines the kernel provided implementation of * vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() * to provide the memory that is used by the Idle task and Timer task - * respectively. The application can provide it's own implementation of + * respectively. The application can provide its own implementation of * vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() by * setting configKERNEL_PROVIDED_STATIC_MEMORY to 0 or leaving it undefined. */ #define configKERNEL_PROVIDED_STATIC_MEMORY 1 @@ -599,10 +609,10 @@ /* Set configENABLE_MVE to 1 to enable the M-Profile Vector Extension (MVE) * support, or 0 to leave the MVE support disabled. This option is only - * applicable to Cortex-M55 and Cortex-M85 ports as M-Profile Vector Extension - * (MVE) is available only on these architectures. configENABLE_MVE must be left - * undefined, or defined to 0 for the Cortex-M23,Cortex-M33 and Cortex-M35P - * ports. */ + * applicable to Cortex-M52, Cortex-M55, Cortex-M85 and STAR-MC3 ports as + * M-Profile Vector Extension (MVE) is available only on these architectures. + * configENABLE_MVE must be left undefined, or defined to 0 for the + * Cortex-M23,Cortex-M33 and Cortex-M35P ports. */ #define configENABLE_MVE 1 /******************************************************************************/ @@ -650,7 +660,7 @@ #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 -#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_xTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1
diff --git a/Source/include/StackMacros.h b/Source/include/StackMacros.h index a500ccb..9acfa18 100644 --- a/Source/include/StackMacros.h +++ b/Source/include/StackMacros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/atomic.h b/Source/include/atomic.h index 0a75b94..6bacfad 100644 --- a/Source/include/atomic.h +++ b/Source/include/atomic.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/croutine.h b/Source/include/croutine.h index b9aa577..07ca2bd 100644 --- a/Source/include/croutine.h +++ b/Source/include/croutine.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -246,7 +246,10 @@ * \defgroup crSTART crSTART * \ingroup Tasks */ + +/* *INDENT-OFF* */ #define crEND() } +/* *INDENT-ON* */ /* * These macros are intended for internal use by the co-routine implementation @@ -525,7 +528,7 @@ * functions used by tasks. * * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to - * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * pass data between a co-routine and ISR, whereas xQueueSendFromISR() and * xQueueReceiveFromISR() can only be used to pass data between a task and and * ISR. * @@ -625,7 +628,7 @@ * functions used by tasks. * * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to - * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * pass data between a co-routine and ISR, whereas xQueueSendFromISR() and * xQueueReceiveFromISR() can only be used to pass data between a task and and * ISR. *
diff --git a/Source/include/deprecated_definitions.h b/Source/include/deprecated_definitions.h index 1718a32..ce0d555 100644 --- a/Source/include/deprecated_definitions.h +++ b/Source/include/deprecated_definitions.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/event_groups.h b/Source/include/event_groups.h index ef14e78..1120183 100644 --- a/Source/include/event_groups.h +++ b/Source/include/event_groups.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -452,13 +452,10 @@ * \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR * \ingroup EventGroup */ -#if ( configUSE_TRACE_FACILITY == 1 ) +#if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; -#else - #define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) \ - xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) ( xEventGroup ), ( uint32_t ) ( uxBitsToClear ), NULL ) -#endif +#endif /* if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ /** * event_groups.h @@ -607,14 +604,11 @@ * \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR * \ingroup EventGroup */ -#if ( configUSE_TRACE_FACILITY == 1 ) +#if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; -#else - #define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) \ - xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) ( xEventGroup ), ( uint32_t ) ( uxBitsToSet ), ( pxHigherPriorityTaskWoken ) ) -#endif +#endif /* if ( ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ /** * event_groups.h
diff --git a/Source/include/list.h b/Source/include/list.h index 7de4d36..769b047 100644 --- a/Source/include/list.h +++ b/Source/include/list.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -31,7 +31,7 @@ * heavily for the schedulers needs, it is also available for use by * application code. * - * list_ts can only store pointers to list_item_ts. Each ListItem_t contains a + * List_t can only store pointers to ListItem_t. Each ListItem_t contains a * numeric value (xItemValue). Most of the time the lists are sorted in * ascending item value order. * @@ -42,9 +42,9 @@ * is because the tail contains a wrap back pointer to the true head of * the list. * - * In addition to it's value, each list item contains a pointer to the next + * In addition to its value, each list item contains a pointer to the next * item in the list (pxNext), a pointer to the list it is in (pxContainer) - * and a pointer to back to the object that contains it. These later two + * and a pointer back to the object that contains it. These later two * pointers are included for efficiency of list manipulation. There is * effectively a two way link between the object containing the list item and * the list item itself. @@ -74,7 +74,7 @@ * compiler's options were set for maximum optimisation has been inspected and * deemed to be as intended. That said, as compiler technology advances, and * especially if aggressive cross module optimisation is used (a use case that - * has not been exercised to any great extend) then it is feasible that the + * has not been exercised to any great extent) then it is feasible that the * volatile qualifier will be needed for correct optimisation. It is expected * that a compiler removing essential code because, without the volatile * qualifier on the list structure members and with aggressive cross module @@ -92,7 +92,7 @@ */ #ifndef configLIST_VOLATILE #define configLIST_VOLATILE -#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */ +#endif /* configLIST_VOLATILE */ /* *INDENT-OFF* */ #ifdef __cplusplus @@ -191,7 +191,7 @@ * Access macro to get the owner of a list item. The owner of a list item * is the object (usually a TCB) that contains the list item. * - * \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \page listGET_LIST_ITEM_OWNER listGET_LIST_ITEM_OWNER * \ingroup LinkedList */ #define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner ) @@ -219,7 +219,7 @@ * Access macro to retrieve the value of the list item at the head of a given * list. * - * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \page listGET_ITEM_VALUE_OF_HEAD_ENTRY listGET_ITEM_VALUE_OF_HEAD_ENTRY * \ingroup LinkedList */ #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) @@ -310,7 +310,7 @@ * Remove an item from a list. The list item has a pointer to the list that * it is in, so only the list item need be passed into the function. * - * @param uxListRemove The item to be removed. The item will remove itself from + * @param pxItemToRemove The item to be removed. The item will remove itself from * the list pointed to by it's pxContainer parameter. * * @return The number of items that remain in the list after the list item has @@ -491,7 +491,7 @@ * Remove an item from a list. The list item has a pointer to the list that * it is in, so only the list item need be passed into the function. * - * @param uxListRemove The item to be removed. The item will remove itself from + * @param pxItemToRemove The item to be removed. The item will remove itself from * the list pointed to by it's pxContainer parameter. * * @return The number of items that remain in the list after the list item has
diff --git a/Source/include/message_buffer.h b/Source/include/message_buffer.h index 5c4d15b..cba18d3 100644 --- a/Source/include/message_buffer.h +++ b/Source/include/message_buffer.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -560,14 +560,14 @@ * * Example use: * @code{c} - * void vAFunction( MessageBuffer_t xMessageBuffer ) + * void vAFunction( MessageBufferHandle_t xMessageBuffer ) * { * uint8_t ucRxData[ 20 ]; * size_t xReceivedBytes; * const TickType_t xBlockTime = pdMS_TO_TICKS( 20 ); * * // Receive the next message from the message buffer. Wait in the Blocked - * // state (so not using any CPU processing time) for a maximum of 100ms for + * // state (so not using any CPU processing time) for a maximum of 20ms for * // a message to become available. * xReceivedBytes = xMessageBufferReceive( xMessageBuffer, * ( void * ) ucRxData, @@ -655,7 +655,7 @@ * Example use: * @code{c} * // A message buffer that has already been created. - * MessageBuffer_t xMessageBuffer; + * MessageBufferHandle_t xMessageBuffer; * * void vAnInterruptServiceRoutine( void ) * {
diff --git a/Source/include/mpu_prototypes.h b/Source/include/mpu_prototypes.h index 3a2bff5..00d8c09 100644 --- a/Source/include/mpu_prototypes.h +++ b/Source/include/mpu_prototypes.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -369,6 +369,9 @@ BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +BaseType_t MPU_xTimerDelete( TimerHandle_t xTimer, + TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + /* MPU versions of event_group.h API functions. */ EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, @@ -409,13 +412,16 @@ BaseType_t MPU_xEventGroupGetStaticBuffer( EventGroupHandle_t xEventGroup, StaticEventGroup_t ** ppxEventGroupBuffer ) PRIVILEGED_FUNCTION; -BaseType_t MPU_xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, - const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; -BaseType_t MPU_xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, - const EventBits_t uxBitsToSet, - BaseType_t * pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; EventBits_t MPU_xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; +#if ( configUSE_MPU_WRAPPERS_V1 == 0 ) + BaseType_t MPU_xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToClear ) FREERTOS_SYSTEM_CALL; + BaseType_t MPU_xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToSet, + BaseType_t * pxHigherPriorityTaskWoken ) FREERTOS_SYSTEM_CALL; +#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ + /* MPU versions of message/stream_buffer.h API functions. */ size_t MPU_xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, const void * pvTxData,
diff --git a/Source/include/mpu_syscall_numbers.h b/Source/include/mpu_syscall_numbers.h index 7203a3a..4531bb2 100644 --- a/Source/include/mpu_syscall_numbers.h +++ b/Source/include/mpu_syscall_numbers.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/mpu_wrappers.h b/Source/include/mpu_wrappers.h index 1bad3a2..9779036 100644 --- a/Source/include/mpu_wrappers.h +++ b/Source/include/mpu_wrappers.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -190,6 +190,7 @@ #define xTimerCreateStatic MPU_xTimerCreateStatic #define xTimerGetStaticBuffer MPU_xTimerGetStaticBuffer #define xTimerGenericCommandFromISR MPU_xTimerGenericCommandFromISR + #define xTimerDelete MPU_xTimerDelete #endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ /* Map standard event_group.h API functions to the MPU equivalents. */ @@ -249,6 +250,9 @@ #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) #define vGrantAccessToTask( xTask, xTaskToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xTaskToGrantAccess ) ) + +/* A privileged task must revoke access to the object before deletion, + * otherwise index reuse may result in accidental permissions. */ #define vRevokeAccessToTask( xTask, xTaskToRevokeAccess ) vRevokeAccessToKernelObject( ( xTask ), ( int32_t ) ( xTaskToRevokeAccess ) ) #define vGrantAccessToSemaphore( xTask, xSemaphoreToGrantAccess ) vGrantAccessToKernelObject( ( xTask ), ( int32_t ) ( xSemaphoreToGrantAccess ) )
diff --git a/Source/include/newlib-freertos.h b/Source/include/newlib-freertos.h index 3aa344a..11435e8 100644 --- a/Source/include/newlib-freertos.h +++ b/Source/include/newlib-freertos.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/picolibc-freertos.h b/Source/include/picolibc-freertos.h index 677205d..641b55f 100644 --- a/Source/include/picolibc-freertos.h +++ b/Source/include/picolibc-freertos.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/portable.h b/Source/include/portable.h index 601062a..aa23e2d 100644 --- a/Source/include/portable.h +++ b/Source/include/portable.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/projdefs.h b/Source/include/projdefs.h index c9ac64a..ceaadf4 100644 --- a/Source/include/projdefs.h +++ b/Source/include/projdefs.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/queue.h b/Source/include/queue.h index 7c8e0de..48ea4db 100644 --- a/Source/include/queue.h +++ b/Source/include/queue.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -44,7 +44,7 @@ /** * Type by which queues are referenced. For example, a call to xQueueCreate() - * returns an QueueHandle_t variable that can then be used as a parameter to + * returns a QueueHandle_t variable that can then be used as a parameter to * xQueueSend(), xQueueReceive(), etc. */ struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */ @@ -60,7 +60,7 @@ /** * Queue sets can contain both queues and semaphores, so the * QueueSetMemberHandle_t is defined as a type to be used where a parameter or - * return value can be either an QueueHandle_t or an SemaphoreHandle_t. + * return value can be either a QueueHandle_t or a SemaphoreHandle_t. */ typedef struct QueueDefinition * QueueSetMemberHandle_t; @@ -185,7 +185,7 @@ * @param pucQueueStorage If uxItemSize is not zero then * pucQueueStorage must point to a uint8_t array that is at least large * enough to hold the maximum number of items that can be in the queue at any - * one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is + * one time - which is ( uxQueueLength * uxItemSize ) bytes. If uxItemSize is * zero then pucQueueStorage can be NULL. * * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which @@ -202,8 +202,8 @@ * char ucData[ 20 ]; * }; * - #define QUEUE_LENGTH 10 - #define ITEM_SIZE sizeof( uint32_t ) + * #define QUEUE_LENGTH 10 + * #define ITEM_SIZE sizeof( uint32_t ) * * // xQueueBuffer will hold the queue structure. * StaticQueue_t xQueueBuffer; @@ -217,10 +217,10 @@ * QueueHandle_t xQueue1; * * // Create a queue capable of containing 10 uint32_t values. - * xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold. - * ITEM_SIZE // The size of each item in the queue - * &( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue. - * &xQueueBuffer ); // The buffer that will hold the queue structure. + * xQueue1 = xQueueCreateStatic( QUEUE_LENGTH, // The number of items the queue can hold. + * ITEM_SIZE, // The size of each item in the queue. + * &( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue. + * &xQueueBuffer ); // The buffer that will hold the queue structure. * * // The queue is guaranteed to be created successfully as no dynamic memory * // allocation is used. Therefore xQueue1 is now a handle to a valid queue. @@ -604,7 +604,7 @@ * BaseType_t xQueueGenericSend( * QueueHandle_t xQueue, * const void * pvItemToQueue, - * TickType_t xTicksToWait + * TickType_t xTicksToWait, * BaseType_t xCopyPosition * ); * @endcode @@ -1026,7 +1026,11 @@ * // Now the buffer is empty we can switch context if necessary. * if( xHigherPriorityTaskWoken ) * { - * taskYIELD (); + * // As xHigherPriorityTaskWoken is now set to pdTRUE then a context + * // switch should be requested. The macro used is port specific and + * // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - + * // refer to the documentation page for the port being used. + * portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); * } * } * @endcode @@ -1098,7 +1102,11 @@ * // Now the buffer is empty we can switch context if necessary. * if( xHigherPriorityTaskWoken ) * { - * taskYIELD (); + * // As xHigherPriorityTaskWoken is now set to pdTRUE then a context + * // switch should be requested. The macro used is port specific and + * // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - + * // refer to the documentation page for the port being used. + * portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); * } * } * @endcode @@ -1181,7 +1189,7 @@ * * // ... * - * if( xHigherPrioritytaskWoken == pdTRUE ) + * if( xHigherPriorityTaskWoken == pdTRUE ) * { * // Writing to the queue caused a task to unblock and the unblocked task * // has a priority higher than or equal to the priority of the currently @@ -1429,23 +1437,27 @@ * // ISR that outputs all the characters received on the queue. * void vISR_Routine( void ) * { - * BaseType_t xTaskWokenByReceive = pdFALSE; + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; * char cRxedChar; * - * while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) ) + * while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xHigherPriorityTaskWoken) ) * { * // A character was received. Output the character now. * vOutputCharacter( cRxedChar ); * * // If removing the character from the queue woke the task that was - * // posting onto the queue xTaskWokenByReceive will have been set to + * // posting onto the queue xHigherPriorityTaskWoken will have been set to * // pdTRUE. No matter how many times this loop iterates only one * // task will be woken. * } * - * if( xTaskWokenByReceive != ( char ) pdFALSE; + * if( xHigherPriorityTaskWoken == pdTRUE ) * { - * taskYIELD (); + * // As xHigherPriorityTaskWoken is now set to pdTRUE then a context + * // switch should be requested. The macro used is port specific and + * // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - + * // refer to the documentation page for the port being used. + * portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); * } * } * @endcode @@ -1652,7 +1664,7 @@ * Note 2: Blocking on a queue set that contains a mutex will not cause the * mutex holder to inherit the priority of the blocked task. * - * Note 3: An additional 4 bytes of RAM is required for each space in a every + * Note 3: An additional 4 bytes of RAM is required for each space in every * queue added to a queue set. Therefore counting semaphores that have a high * maximum count value should not be added to a queue set. * @@ -1704,7 +1716,7 @@ * Note 2: Blocking on a queue set that contains a mutex will not cause the * mutex holder to inherit the priority of the blocked task. * - * Note 3: An additional 4 bytes of RAM is required for each space in a every + * Note 3: An additional 4 bytes of RAM is required for each space in every * queue added to a queue set. Therefore counting semaphores that have a high * maximum count value should not be added to a queue set. * @@ -1755,7 +1767,7 @@ * a call to xQueueSelectFromSet() has first returned a handle to that set member. * * @param xQueueOrSemaphore The handle of the queue or semaphore being added to - * the queue set (cast to an QueueSetMemberHandle_t type). + * the queue set (cast to a QueueSetMemberHandle_t type). * * @param xQueueSet The handle of the queue set to which the queue or semaphore * is being added. @@ -1778,7 +1790,7 @@ * function. * * @param xQueueOrSemaphore The handle of the queue or semaphore being removed - * from the queue set (cast to an QueueSetMemberHandle_t type). + * from the queue set (cast to a QueueSetMemberHandle_t type). * * @param xQueueSet The handle of the queue set in which the queue or semaphore * is included. @@ -1824,7 +1836,7 @@ * a QueueSetMemberHandle_t type) contained in the queue set that contains data, * or the handle of a semaphore (cast to a QueueSetMemberHandle_t type) contained * in the queue set that is available, or NULL if no such queue or semaphore - * exists before before the specified block time expires. + * exists before the specified block time expires. */ #if ( configUSE_QUEUE_SETS == 1 ) QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
diff --git a/Source/include/semphr.h b/Source/include/semphr.h index 4767514..7d16072 100644 --- a/Source/include/semphr.h +++ b/Source/include/semphr.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -37,8 +37,8 @@ typedef QueueHandle_t SemaphoreHandle_t; -#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U ) -#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) +#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( UBaseType_t ) 1U ) +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0U ) #define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
diff --git a/Source/include/stack_macros.h b/Source/include/stack_macros.h index 20acaf3..fc63278 100644 --- a/Source/include/stack_macros.h +++ b/Source/include/stack_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/stdint.readme b/Source/include/stdint.readme index 517a77e..af5978f 100644 --- a/Source/include/stdint.readme +++ b/Source/include/stdint.readme
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/include/stream_buffer.h b/Source/include/stream_buffer.h index b257b82..321baa6 100644 --- a/Source/include/stream_buffer.h +++ b/Source/include/stream_buffer.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -760,7 +760,7 @@ * * Example use: * @code{c} - * void vAFunction( StreamBuffer_t xStreamBuffer ) + * void vAFunction( StreamBufferHandle_t xStreamBuffer ) * { * uint8_t ucRxData[ 20 ]; * size_t xReceivedBytes; @@ -768,7 +768,7 @@ * * // Receive up to another sizeof( ucRxData ) bytes from the stream buffer. * // Wait in the Blocked state (so not using any CPU processing time) for a - * // maximum of 100ms for the full sizeof( ucRxData ) number of bytes to be + * // maximum of 20ms for the full sizeof( ucRxData ) number of bytes to be * // available. * xReceivedBytes = xStreamBufferReceive( xStreamBuffer, * ( void * ) ucRxData, @@ -840,7 +840,7 @@ * Example use: * @code{c} * // A stream buffer that has already been created. - * StreamBuffer_t xStreamBuffer; + * StreamBufferHandle_t xStreamBuffer; * * void vAnInterruptServiceRoutine( void ) * { @@ -1218,7 +1218,7 @@ * stream_buffer.h * * @code{c} - * void vStreamBufferSetStreamBufferNotificationIndex ( StreamBuffer_t xStreamBuffer, UBaseType_t uxNotificationIndex ); + * void vStreamBufferSetStreamBufferNotificationIndex ( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxNotificationIndex ); * @endcode * * Set the task notification index used for the supplied stream buffer.
diff --git a/Source/include/task.h b/Source/include/task.h index b910197..09f1875 100644 --- a/Source/include/task.h +++ b/Source/include/task.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -53,10 +54,10 @@ * The tskKERNEL_VERSION_MAJOR, tskKERNEL_VERSION_MINOR, tskKERNEL_VERSION_BUILD * values will reflect the last released version number. */ -#define tskKERNEL_VERSION_NUMBER "V11.2.0" +#define tskKERNEL_VERSION_NUMBER "V11.3.1" #define tskKERNEL_VERSION_MAJOR 11 -#define tskKERNEL_VERSION_MINOR 2 -#define tskKERNEL_VERSION_BUILD 0 +#define tskKERNEL_VERSION_MINOR 3 +#define tskKERNEL_VERSION_BUILD 1 /* MPU region parameters passed in ulParameters * of MemoryRegion_t struct. */ @@ -68,24 +69,27 @@ #if defined( portARMV8M_MINOR_VERSION ) && ( portARMV8M_MINOR_VERSION >= 1 ) #define tskMPU_REGION_PRIVILEGED_EXECUTE_NEVER ( 1U << 5U ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ +#define tskMPU_REGION_NON_SHAREABLE ( 1U << 6U ) +#define tskMPU_REGION_OUTER_SHAREABLE ( 1U << 7U ) +#define tskMPU_REGION_INNER_SHAREABLE ( 1U << 8U ) /* MPU region permissions stored in MPU settings to * authorize access requests. */ -#define tskMPU_READ_PERMISSION ( 1U << 0U ) -#define tskMPU_WRITE_PERMISSION ( 1U << 1U ) +#define tskMPU_READ_PERMISSION ( 1U << 0U ) +#define tskMPU_WRITE_PERMISSION ( 1U << 1U ) /* The direct to task notification feature used to have only a single notification * per task. Now there is an array of notifications per task that is dimensioned by * configTASK_NOTIFICATION_ARRAY_ENTRIES. For backward compatibility, any use of the * original direct to task notification defaults to using the first index in the * array. */ -#define tskDEFAULT_INDEX_TO_NOTIFY ( 0 ) +#define tskDEFAULT_INDEX_TO_NOTIFY ( 0 ) /** * task. h * * Type by which tasks are referenced. For example, a call to xTaskCreate - * returns (via a pointer parameter) an TaskHandle_t variable that can then + * returns (via a pointer parameter) a TaskHandle_t variable that can then * be used as a parameter to vTaskDelete to delete the task. * * \defgroup TaskHandle_t TaskHandle_t @@ -180,6 +184,13 @@ #endif } TaskStatus_t; +/* Callback type used by uxTaskCallForEachTask(). The callback receives one + * task handle and state at a time, plus an opaque caller-supplied context + * pointer. The callback may call vTaskGetInfo() if it needs a TaskStatus_t. */ +typedef void (* TaskStatusCallbackFunction_t)( TaskHandle_t xTask, + eTaskState eState, + void * pvCallbackContext ); + /* Possible return values for eTaskConfirmSleepModeStatus(). */ typedef enum { @@ -544,6 +555,14 @@ * The function parameters define the memory regions and associated access * permissions allocated to the task. * + * The parameter macros used in MemoryRegion_t.ulParameters are port specific. + * Some ports, including the Cortex-M3/4 MPU ports, use the portMPU_REGION_* + * values shown below. + * ARMv8-M MPU ports, such as CM23, CM33, CM52, CM55, CM85 and STAR_MC3, use + * the tskMPU_REGION_* values defined in this header; the port translates them + * into MPU register settings. Check the selected port's headers before selecting + * the region parameter macros. + * * See xTaskCreateRestrictedStatic() for a version that does not use any * dynamic memory allocation. * @@ -560,7 +579,7 @@ * * Example usage: * @code{c} - * // Create an TaskParameters_t structure that defines the task to be created. + * // Create a TaskParameters_t structure that defines the task to be created. * static const TaskParameters_t xCheckTaskParameters = * { * vATask, // pvTaskCode - the function that implements the task. @@ -602,12 +621,12 @@ * \defgroup xTaskCreateRestricted xTaskCreateRestricted * \ingroup Tasks */ -#if ( portUSING_MPU_WRAPPERS == 1 ) +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * pxCreatedTask ) PRIVILEGED_FUNCTION; #endif -#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) BaseType_t xTaskCreateRestrictedAffinitySet( const TaskParameters_t * const pxTaskDefinition, UBaseType_t uxCoreAffinityMask, TaskHandle_t * pxCreatedTask ) PRIVILEGED_FUNCTION; @@ -635,6 +654,14 @@ * xTaskCreateRestrictedStatic() therefore allows a memory protected task to be * created without using any dynamic memory allocation. * + * The parameter macros used in MemoryRegion_t.ulParameters are port specific. + * Some ports, including the Cortex-M3/4 MPU ports, use the portMPU_REGION_* + * values shown below. + * ARMv8-M MPU ports, such as CM23, CM33, CM52, CM55, CM85 and STAR_MC3, use + * the tskMPU_REGION_* values defined in this header; the port translates them + * into MPU register settings. Check the selected port's headers before selecting + * the region parameter macros. + * * @param pxTaskDefinition Pointer to a structure that contains a member * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API * documentation) plus an optional stack buffer and the memory region @@ -650,7 +677,7 @@ * * Example usage: * @code{c} - * // Create an TaskParameters_t structure that defines the task to be created. + * // Create a TaskParameters_t structure that defines the task to be created. * // The StaticTask_t variable is only included in the structure when * // configSUPPORT_STATIC_ALLOCATION is set to 1. The PRIVILEGED_DATA macro can * // be used to force the variable into the RTOS kernel's privileged data area. @@ -724,6 +751,14 @@ * @param[in] pxRegions A pointer to a MemoryRegion_t structure that contains the * new memory region definitions. * + * The parameter macros used in MemoryRegion_t.ulParameters are port specific. + * Some ports, including the Cortex-M3/4 MPU ports, use the portMPU_REGION_* + * values shown below. + * ARMv8-M MPU ports, such as CM23, CM33, CM52, CM55, CM85 and STAR_MC3, use + * the tskMPU_REGION_* values defined in this header; the port translates them + * into MPU register settings. Check the selected port's headers before selecting + * the region parameter macros. + * * Example usage: * @code{c} * // Define an array of MemoryRegion_t structures that configures an MPU region @@ -861,6 +896,43 @@ /** * task. h * @code{c} + * TickType_t xTaskPeriodicDelay( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement ); + * @endcode + * + * INCLUDE_xTaskDelayUntil must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Periodic task delay to ensure a constant execution frequency. + * + * This function is similar to xTaskDelayUntil () with a few important differences: + * - pxPreviousWakeTime contains the last past wake time, so it never runs away + * - if you suspend the task, when you resume it pxPreviousWakeTime will instantly + * catch up all skipped increments + * - it returns the number of increments added to pxPreviosWakeTime + * + * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the + * task was last unblocked. The variable must be initialised with the current time + * prior to its first use. Following this the variable is automatically updated. + * + * @param xTimeIncrement The cycle time period. The task will be unblocked at + * time *pxPreviousWakeTime + xTimeIncrement. Passing the same xTimeIncrement + * parameter value will cause the task to execute with a fixed interval. + * + * @return Number of times xTimeIncrement has been added to pxPreviousWakeTime. + * It is 0 on the first call or if not enough ticks have been elapsed since the + * last call, 1 in normal circumstances or more than 1 if some period has been + * skipped for some reason (e.g. when the caller task is suspended for more than + * xTimeIncrement ticks). + * + * \defgroup xTaskPeriodicDelay xTaskPeriodicDelay + * \ingroup TaskCtrl + */ +TickType_t xTaskPeriodicDelay( TickType_t * const pxPreviousWakeTime, + const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION; + +/** + * task. h + * @code{c} * BaseType_t xTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement ); * @endcode * @@ -897,7 +969,8 @@ * * @return Value which can be used to check whether the task was actually delayed. * Will be pdTRUE if the task way delayed and pdFALSE otherwise. A task will not - * be delayed if the next expected wake time is in the past. + * be delayed if the next expected wake time is in the past. This prevents periodic + * tasks from accumulating delays and allows them to resume their regular timing pattern. * * Example usage: * @code{c} @@ -1002,7 +1075,7 @@ * // it itself. * if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY ) * { - * // The task has changed it's priority. + * // The task has changed its priority. * } * * // ... @@ -1045,7 +1118,7 @@ * * @return The base priority of xTask. * - * \defgroup uxTaskPriorityGet uxTaskBasePriorityGet + * \defgroup uxTaskBasePriorityGet uxTaskBasePriorityGet * \ingroup TaskCtrl */ UBaseType_t uxTaskBasePriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; @@ -2084,7 +2157,7 @@ * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for * uxTaskGetSystemState() to be available. * - * uxTaskGetSystemState() populates an TaskStatus_t structure for each task in + * uxTaskGetSystemState() populates a TaskStatus_t structure for each task in * the system. TaskStatus_t structures contain, among other things, members * for the task handle, task name, task priority, task state, and total amount * of run time consumed by the task. See the TaskStatus_t structure @@ -2181,7 +2254,38 @@ UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION; -#endif + + +/** + * For each task, call pxCallbackFunction with the task's handle and state, + * and the provided context. + * + * NOTE: This function is intended for debugging use only as it suspends + * the scheduler for an extended period. The callback runs while the + * scheduler is suspended, so it must return quickly and must not perform + * blocking operations. + * + * NOTE: This API is privileged-only (it invokes a user callback from + * privileged context). + * + * @param pxCallbackFunction Callback to invoke once for each task (passing + * the task's handle, state, and the pvCallbackContext). + * + * @param pvCallbackContext Opaque caller-provided context passed through to + * each callback invocation. + * + * @param pulTotalRunTime If configGENERATE_RUN_TIME_STATS is set to 1 in + * FreeRTOSConfig.h then *pulTotalRunTime is set to the total run time since + * boot. pulTotalRunTime can be set to NULL to omit the total run time + * information. + * + * @return The number tasks provided to the callback. + */ + UBaseType_t uxTaskCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext, + configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) PRIVILEGED_FUNCTION; + +#endif /* if ( configUSE_TRACE_FACILITY == 1 ) */ /** * task. h @@ -2612,9 +2716,8 @@ * notification value at that index being updated. ulValue is not used and * xTaskNotifyIndexed() always returns pdPASS in this case. * - * pulPreviousNotificationValue - - * Can be used to pass out the subject task's notification value before any - * bits are modified by the notify function. + * @param pulPreviousNotificationValue Can be used to pass out the subject + * task's notification value before any bits are modified by the notify function. * * @return Dependent on the value of eAction. See the description of the * eAction parameter. @@ -2759,6 +2862,9 @@ * updated. ulValue is not used and xTaskNotify() always returns pdPASS in * this case. * + * @param pulPreviousNotificationValue Can be used to pass out the subject + * task's notification value before any bits are modified by the notify function. + * * @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the * task to which the notification was sent to leave the Blocked state, and the @@ -3201,7 +3307,7 @@ /** * task. h * @code{c} - * BaseType_t xTaskNotifyStateClearIndexed( TaskHandle_t xTask, UBaseType_t uxIndexToCLear ); + * BaseType_t xTaskNotifyStateClearIndexed( TaskHandle_t xTask, UBaseType_t uxIndexToClear ); * * BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); * @endcode
diff --git a/Source/include/timers.h b/Source/include/timers.h index 2e809c0..7f0c85c 100644 --- a/Source/include/timers.h +++ b/Source/include/timers.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -667,8 +667,13 @@ * * See the xTimerChangePeriod() API function example usage scenario. */ -#define xTimerDelete( xTimer, xTicksToWait ) \ +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) + BaseType_t xTimerDelete( TimerHandle_t xTimer, + TickType_t xTicksToWait ); +#else + #define xTimerDelete( xTimer, xTicksToWait ) \ xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xTicksToWait ) ) +#endif /** * BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );
diff --git a/Source/list.c b/Source/list.c index b390c5a..c6ef877 100644 --- a/Source/list.c +++ b/Source/list.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/ARMClang/Use-the-GCC-ports.txt b/Source/portable/ARMClang/Use-the-GCC-ports.txt new file mode 100644 index 0000000..9dd1bc7 --- /dev/null +++ b/Source/portable/ARMClang/Use-the-GCC-ports.txt
@@ -0,0 +1,2 @@ +The FreeRTOS GCC port layer also builds and works with the ARMClang compiler. +To use the ARMClang compiler build the port files from FreeRTOS/Source/portable/GCC.
diff --git a/Source/portable/Common/mpu_wrappers.c b/Source/portable/Common/mpu_wrappers.c index a26021b..0778977 100644 --- a/Source/portable/Common/mpu_wrappers.c +++ b/Source/portable/Common/mpu_wrappers.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/Common/mpu_wrappers_v2.c b/Source/portable/Common/mpu_wrappers_v2.c index ac1159b..b81bf0f 100644 --- a/Source/portable/Common/mpu_wrappers_v2.c +++ b/Source/portable/Common/mpu_wrappers_v2.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -1059,8 +1059,8 @@ configRUN_TIME_COUNTER_TYPE * pulTotalRunTime ) /* PRIVILEGED_FUNCTION */ { UBaseType_t uxReturn = 0; - UBaseType_t xIsTaskStatusArrayWriteable = pdFALSE; - UBaseType_t xIsTotalRunTimeWriteable = pdFALSE; + BaseType_t xIsTaskStatusArrayWriteable = pdFALSE; + BaseType_t xIsTotalRunTimeWriteable = pdFALSE; uint32_t ulArraySize = ( uint32_t ) uxArraySize; uint32_t ulTaskStatusSize = ( uint32_t ) sizeof( TaskStatus_t ); @@ -3890,6 +3890,40 @@ #endif /* if ( configUSE_TIMERS == 1 ) */ /*-----------------------------------------------------------*/ + #if ( configUSE_TIMERS == 1 ) + + BaseType_t MPU_xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait ) /* PRIVILEGED_FUNCTION */ + { + BaseType_t xReturn = pdFALSE; + TimerHandle_t xInternalTimerHandle = NULL; + int32_t lIndex; + + lIndex = ( int32_t ) xTimer; + + if( IS_EXTERNAL_INDEX_VALID( lIndex ) != pdFALSE ) + { + xInternalTimerHandle = MPU_GetTimerHandleAtIndex( CONVERT_TO_INTERNAL_INDEX( lIndex ) ); + + if( xInternalTimerHandle != NULL ) + { + xReturn = xTimerGenericCommandFromTask( xInternalTimerHandle, + tmrCOMMAND_DELETE, + 0U, /* xOptionalValue */ + NULL, /* pxHigherPriorityTaskWoken */ + xTicksToWait ); + if( xReturn != pdFALSE ) + { + MPU_SetIndexFreeInKernelObjectPool( CONVERT_TO_INTERNAL_INDEX( lIndex ) ); + } + } + } + + return xReturn; + } + + #endif /* if ( configUSE_TIMERS == 1 ) */ +/*-----------------------------------------------------------*/ + /*-----------------------------------------------------------*/ /* MPU wrappers for event group APIs. */ /*-----------------------------------------------------------*/ @@ -4282,7 +4316,7 @@ #endif /* #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_EVENT_GROUPS == 1 ) ) */ /*-----------------------------------------------------------*/ - #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) BaseType_t MPU_xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) /* PRIVILEGED_FUNCTION */ @@ -4306,10 +4340,10 @@ return xReturn; } - #endif /* #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ + #endif /* #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ /*-----------------------------------------------------------*/ - #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) BaseType_t MPU_xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, @@ -4334,7 +4368,7 @@ return xReturn; } - #endif /* #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ + #endif /* #if ( ( configUSE_EVENT_GROUPS == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */ /*-----------------------------------------------------------*/ #if ( configUSE_EVENT_GROUPS == 1 )
diff --git a/Source/portable/GCC/ARM_CA9/port.c b/Source/portable/GCC/ARM_CA9/port.c index cb724d0..5ac0d16 100644 --- a/Source/portable/GCC/ARM_CA9/port.c +++ b/Source/portable/GCC/ARM_CA9/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CA9/portASM.S b/Source/portable/GCC/ARM_CA9/portASM.S index 61caf27..dfdbad8 100644 --- a/Source/portable/GCC/ARM_CA9/portASM.S +++ b/Source/portable/GCC/ARM_CA9/portASM.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CA9/portmacro.h b/Source/portable/GCC/ARM_CA9/portmacro.h index 76255db..57ebf9c 100644 --- a/Source/portable/GCC/ARM_CA9/portmacro.h +++ b/Source/portable/GCC/ARM_CA9/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM0/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM0/mpu_wrappers_v2_asm.c index 2a7af2e..6d7194b 100644 --- a/Source/portable/GCC/ARM_CM0/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM0/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM0/port.c b/Source/portable/GCC/ARM_CM0/port.c index e9ef847..e51ed32 100644 --- a/Source/portable/GCC/ARM_CM0/port.c +++ b/Source/portable/GCC/ARM_CM0/port.c
@@ -1,6 +1,8 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2025 Arm Limited and/or its affiliates + * <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -687,7 +689,7 @@ } /* Shift the code by one before returning so it can be written directly - * into the the correct bit position of the attribute register. */ + * into the correct bit position of the attribute register. */ return( ulReturnValue << 1UL ); } @@ -915,7 +917,10 @@ xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; uint32_t ulSystemCallLocation, i; - const uint32_t ulStackFrameSize = 8; + /* Hardware Saved Stack Frame Size upon Exception entry: + * Basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + */ + const uint32_t ulHardwareSavedExceptionFrameSize = 8; #if defined( __ARMCC_VERSION ) @@ -955,10 +960,10 @@ pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -981,7 +986,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1036,7 +1041,10 @@ xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; uint32_t ulSystemCallLocation, i; - const uint32_t ulStackFrameSize = 8; + /* Hardware Saved Stack Frame Size upon Exception entry: + * Basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + */ + const uint32_t ulHardwareSavedExceptionFrameSize = 8; #if defined( __ARMCC_VERSION ) @@ -1072,10 +1080,10 @@ pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; }
diff --git a/Source/portable/GCC/ARM_CM0/portasm.c b/Source/portable/GCC/ARM_CM0/portasm.c index 2280ec8..ec95ddb 100644 --- a/Source/portable/GCC/ARM_CM0/portasm.c +++ b/Source/portable/GCC/ARM_CM0/portasm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -111,9 +111,9 @@ " restore_general_regs_first_task: \n" " subs r1, #32 \n" " ldmia r1!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy half of the hardware saved context on the task stack. */ " ldmia r1!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy rest half of the hardware saved context on the task stack. */ " subs r1, #48 \n" " ldmia r1!, {r4-r7} \n" /* Restore r8-r11. */ " mov r8, r4 \n" /* r8 = r4. */ @@ -366,9 +366,9 @@ " restore_general_regs: \n" " subs r1, #32 \n" " ldmia r1!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy half of the hardware saved context on the task stack. */ " ldmia r1!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy rest half of the hardware saved context on the task stack. */ " subs r1, #48 \n" " ldmia r1!, {r4-r7} \n" /* Restore r8-r11. */ " mov r8, r4 \n" /* r8 = r4. */
diff --git a/Source/portable/GCC/ARM_CM0/portasm.h b/Source/portable/GCC/ARM_CM0/portasm.h index ce0f3aa..da5c664 100644 --- a/Source/portable/GCC/ARM_CM0/portasm.h +++ b/Source/portable/GCC/ARM_CM0/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM0/portmacro.h b/Source/portable/GCC/ARM_CM0/portmacro.h index 97e8450..2599275 100644 --- a/Source/portable/GCC/ARM_CM0/portmacro.h +++ b/Source/portable/GCC/ARM_CM0/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM23/non_secure/mpu_wrappers_v2_asm.c index a195dbf..a3fc377 100644 --- a/Source/portable/GCC/ARM_CM23/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM23/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/non_secure/port.c b/Source/portable/GCC/ARM_CM23/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM23/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM23/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM23/non_secure/portasm.c b/Source/portable/GCC/ARM_CM23/non_secure/portasm.c index bfc061e..24a8ee1 100644 --- a/Source/portable/GCC/ARM_CM23/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM23/non_secure/portasm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -48,6 +48,12 @@ #endif #if ( configENABLE_MPU == 1 ) + #define SECURE_CONTEXT_OFFSET -20 +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + +#if ( configENABLE_MPU == 1 ) void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */ { @@ -120,9 +126,9 @@ " restore_general_regs_first_task: \n" " subs r2, #32 \n" " ldmia r2!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */ - " stmia r3!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */ + " stmia r3!, {r4-r7} \n" /* Copy half of the hardware saved context on the task stack. */ " ldmia r2!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */ - " stmia r3!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */ + " stmia r3!, {r4-r7} \n" /* Copy rest half of the hardware saved context on the task stack. */ " subs r2, #48 \n" " ldmia r2!, {r4-r7} \n" /* Restore r8-r11. */ " mov r8, r4 \n" /* r8 = r4. */ @@ -396,9 +402,9 @@ " restore_general_regs: \n" " subs r2, #32 \n" " ldmia r2!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */ - " stmia r3!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */ + " stmia r3!, {r4-r7} \n" /* Copy half of the hardware saved context on the task stack. */ " ldmia r2!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */ - " stmia r3!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */ + " stmia r3!, {r4-r7} \n" /* Copy rest half of the hardware saved context on the task stack. */ " subs r2, #48 \n" " ldmia r2!, {r4-r7} \n" /* Restore r8-r11. */ " mov r8, r4 \n" /* r8 = r4. */ @@ -590,15 +596,16 @@ ( " .syntax unified \n" " \n" - " ldr r2, [r0] \n" /* The first item in the TCB is the top of the stack. */ - " ldr r1, [r2] \n" /* The first item on the stack is the task's xSecureContext. */ + " ldr r2, [r0] \n" /* The first item in the TCB is the stored context location. */ + " adds r2, r2, %0 \n" /* r2 = r2 + SECURE_CONTEXT_OFFSET. */ + " ldr r1, [r2] \n" /* Read xSecureContext from the task's context. */ " cmp r1, #0 \n" /* Raise svc if task's xSecureContext is not NULL. */ " bne free_secure_context \n" /* Branch if r1 != 0. */ " bx lr \n" /* There is no secure context (xSecureContext is NULL). */ " free_secure_context: \n" - " svc %0 \n" /* Secure context is freed in the supervisor call. */ + " svc %1 \n" /* Secure context is freed in the supervisor call. */ " bx lr \n" /* Return. */ - ::"i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" + ::"i" ( SECURE_CONTEXT_OFFSET ), "i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/GCC/ARM_CM23/non_secure/portasm.h b/Source/portable/GCC/ARM_CM23/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM23/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM23/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM23/non_secure/portmacro.h index 728e77d..14f73a1 100644 --- a/Source/portable/GCC/ARM_CM23/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM23/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 0 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM23/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM23/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM23/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM23/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_context.c b/Source/portable/GCC/ARM_CM23/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_context.c +++ b/Source/portable/GCC/ARM_CM23/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_context.h b/Source/portable/GCC/ARM_CM23/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_context.h +++ b/Source/portable/GCC/ARM_CM23/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_context_port.c b/Source/portable/GCC/ARM_CM23/secure/secure_context_port.c index d10c7f3..d041d00 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_context_port.c +++ b/Source/portable/GCC/ARM_CM23/secure/secure_context_port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_heap.c b/Source/portable/GCC/ARM_CM23/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_heap.c +++ b/Source/portable/GCC/ARM_CM23/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_heap.h b/Source/portable/GCC/ARM_CM23/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_heap.h +++ b/Source/portable/GCC/ARM_CM23/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_init.c b/Source/portable/GCC/ARM_CM23/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_init.c +++ b/Source/portable/GCC/ARM_CM23/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_init.h b/Source/portable/GCC/ARM_CM23/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_init.h +++ b/Source/portable/GCC/ARM_CM23/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23/secure/secure_port_macros.h b/Source/portable/GCC/ARM_CM23/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/GCC/ARM_CM23/secure/secure_port_macros.h +++ b/Source/portable/GCC/ARM_CM23/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.c index a195dbf..a3fc377 100644 --- a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/port.c b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.c b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.c index 3bf4e27..8f2a11c 100644 --- a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -121,9 +121,9 @@ " restore_general_regs_first_task: \n" " subs r1, #32 \n" " ldmia r1!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy half of the hardware saved context on the task stack. */ " ldmia r1!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy rest half of the hardware saved context on the task stack. */ " subs r1, #48 \n" " ldmia r1!, {r4-r7} \n" /* Restore r8-r11. */ " mov r8, r4 \n" /* r8 = r4. */ @@ -375,9 +375,9 @@ " restore_general_regs: \n" " subs r1, #32 \n" " ldmia r1!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy half of the hardware saved context on the task stack. */ " ldmia r1!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */ - " stmia r2!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */ + " stmia r2!, {r4-r7} \n" /* Copy rest half of the hardware saved context on the task stack. */ " subs r1, #48 \n" " ldmia r1!, {r4-r7} \n" /* Restore r8-r11. */ " mov r8, r4 \n" /* r8 = r4. */
diff --git a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.h b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacro.h index 728e77d..14f73a1 100644 --- a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 0 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM23_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM3/port.c b/Source/portable/GCC/ARM_CM3/port.c index fb32128..54d5567 100644 --- a/Source/portable/GCC/ARM_CM3/port.c +++ b/Source/portable/GCC/ARM_CM3/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM3/portmacro.h b/Source/portable/GCC/ARM_CM3/portmacro.h index 1d0d009..d9a19e4 100644 --- a/Source/portable/GCC/ARM_CM3/portmacro.h +++ b/Source/portable/GCC/ARM_CM3/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM33/non_secure/mpu_wrappers_v2_asm.c index 9c3e8c7..6dd2be8 100644 --- a/Source/portable/GCC/ARM_CM33/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM33/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/non_secure/port.c b/Source/portable/GCC/ARM_CM33/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM33/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM33/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM33/non_secure/portasm.c b/Source/portable/GCC/ARM_CM33/non_secure/portasm.c index bdee088..6bc070d 100644 --- a/Source/portable/GCC/ARM_CM33/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM33/non_secure/portasm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright 2024 Arm Limited and/or its affiliates * <open-source-office@arm.com> @@ -46,6 +46,16 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #if ( configENABLE_MPU == 1 ) + #if ( configENABLE_PAC == 1 ) + #define SECURE_CONTEXT_OFFSET -36 + #else + #define SECURE_CONTEXT_OFFSET -20 + #endif +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + +#if ( configENABLE_MPU == 1 ) void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */ { @@ -609,13 +619,13 @@ ( " .syntax unified \n" " \n" - " ldr r2, [r0] \n" /* The first item in the TCB is the top of the stack. */ - " ldr r1, [r2] \n" /* The first item on the stack is the task's xSecureContext. */ + " ldr r2, [r0] \n" /* The first item in the TCB is the stored context location. */ + " ldr r1, [r2, %0] \n" /* Read xSecureContext from the task's context. */ " cmp r1, #0 \n" /* Raise svc if task's xSecureContext is not NULL. */ " it ne \n" - " svcne %0 \n" /* Secure context is freed in the supervisor call. */ + " svcne %1 \n" /* Secure context is freed in the supervisor call. */ " bx lr \n" /* Return. */ - ::"i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" + ::"i" ( SECURE_CONTEXT_OFFSET ), "i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/GCC/ARM_CM33/non_secure/portasm.h b/Source/portable/GCC/ARM_CM33/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM33/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM33/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM33/non_secure/portmacro.h index a57d2e6..931ba78 100644 --- a/Source/portable/GCC/ARM_CM33/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM33/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM33/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM33/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM33/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM33/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_context.c b/Source/portable/GCC/ARM_CM33/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_context.c +++ b/Source/portable/GCC/ARM_CM33/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_context.h b/Source/portable/GCC/ARM_CM33/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_context.h +++ b/Source/portable/GCC/ARM_CM33/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_context_port.c b/Source/portable/GCC/ARM_CM33/secure/secure_context_port.c index 11d8e1b..ef5cbf7 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_context_port.c +++ b/Source/portable/GCC/ARM_CM33/secure/secure_context_port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_heap.c b/Source/portable/GCC/ARM_CM33/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_heap.c +++ b/Source/portable/GCC/ARM_CM33/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_heap.h b/Source/portable/GCC/ARM_CM33/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_heap.h +++ b/Source/portable/GCC/ARM_CM33/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_init.c b/Source/portable/GCC/ARM_CM33/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_init.c +++ b/Source/portable/GCC/ARM_CM33/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_init.h b/Source/portable/GCC/ARM_CM33/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_init.h +++ b/Source/portable/GCC/ARM_CM33/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33/secure/secure_port_macros.h b/Source/portable/GCC/ARM_CM33/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/GCC/ARM_CM33/secure/secure_port_macros.h +++ b/Source/portable/GCC/ARM_CM33/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.c index 8504ddd..63d1b52 100644 --- a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/port.c b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c index 51ec476..fbb00b1 100644 --- a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -134,8 +133,21 @@ ( " .syntax unified \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 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. */ " \n" #if ( configENABLE_PAC == 1 ) @@ -158,6 +170,14 @@ " mov r0, #0 \n" " msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */ " 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 @@ " clrm {r1-r4} \n" /* Clear r1-r4. */ #endif /* configENABLE_PAC */ " \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 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. */ " \n" " mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */ " msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */ " dsb \n" " isb \n" + #if ( configNUMBER_OF_CORES > 1) + " mov r0, r2 \n" /* r0 = ucPortGetCoreID() */ + #endif /* if ( configNUMBER_OF_CORES == 1) */ " bl vTaskSwitchContext \n" " mov r0, #0 \n" /* r0 = 0. */ " msr basepri, r0 \n" /* Enable interrupts. */ " \n" + #if ( configNUMBER_OF_CORES == 1) " ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( 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. */ " \n" #if ( configENABLE_PAC == 1 ) @@ -458,7 +501,16 @@ " 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. */ " 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 ) */ + ); }
diff --git a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.h b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacro.h index a57d2e6..390ec34 100644 --- a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 1 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM33_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM3_MPU/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM3_MPU/mpu_wrappers_v2_asm.c index 0e0abee..6c2e8ed 100644 --- a/Source/portable/GCC/ARM_CM3_MPU/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM3_MPU/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM3_MPU/port.c b/Source/portable/GCC/ARM_CM3_MPU/port.c index af25ed6..d834fba 100644 --- a/Source/portable/GCC/ARM_CM3_MPU/port.c +++ b/Source/portable/GCC/ARM_CM3_MPU/port.c
@@ -1,6 +1,8 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2025 Arm Limited and/or its affiliates + * <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -53,9 +55,19 @@ #define portNVIC_SYSTICK_CLK ( 0 ) #endif +/* Unprivileged critical sections are not supported when using MPU wrappers + * version 2. Default the option to 0 and reject an explicit value of 1. */ #ifndef configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS - #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." - #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0 + #else + #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #endif +#else + #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) ) + #error configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not supported with MPU wrappers version 2 ( configUSE_MPU_WRAPPERS_V1 == 0 ). + #endif #endif /* Prototype of all Interrupt Service Routines (ISRs). */ @@ -484,7 +496,10 @@ xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; uint32_t ulSystemCallLocation, i; - const uint32_t ulStackFrameSize = 8; + /* Hardware Saved Stack Frame Size upon Exception entry: + * Basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + */ + const uint32_t ulHardwareSavedExceptionFrameSize = 8; #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being @@ -520,10 +535,10 @@ pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -541,7 +556,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Store the value of the Link Register before the SVC was raised. * It contains the address of the caller of the System Call entry @@ -594,7 +609,10 @@ xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; uint32_t ulSystemCallLocation, i; - const uint32_t ulStackFrameSize = 8; + /* Hardware Saved Stack Frame Size upon Exception entry: + * Basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + */ + const uint32_t ulHardwareSavedExceptionFrameSize = 8; #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being @@ -626,10 +644,10 @@ pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1188,7 +1206,7 @@ } /* Shift the code by one before returning so it can be written directly - * into the the correct bit position of the attribute register. */ + * into the correct bit position of the attribute register. */ return( ulReturnValue << 1UL ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/GCC/ARM_CM3_MPU/portmacro.h b/Source/portable/GCC/ARM_CM3_MPU/portmacro.h index 3d8d604..c6ee751 100644 --- a/Source/portable/GCC/ARM_CM3_MPU/portmacro.h +++ b/Source/portable/GCC/ARM_CM3_MPU/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM4F/port.c b/Source/portable/GCC/ARM_CM4F/port.c index df7027a..b321f06 100644 --- a/Source/portable/GCC/ARM_CM4F/port.c +++ b/Source/portable/GCC/ARM_CM4F/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM4F/portmacro.h b/Source/portable/GCC/ARM_CM4F/portmacro.h index f555ef8..fc2a839 100644 --- a/Source/portable/GCC/ARM_CM4F/portmacro.h +++ b/Source/portable/GCC/ARM_CM4F/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM4_MPU/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM4_MPU/mpu_wrappers_v2_asm.c index 0e0abee..6c2e8ed 100644 --- a/Source/portable/GCC/ARM_CM4_MPU/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM4_MPU/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM4_MPU/port.c b/Source/portable/GCC/ARM_CM4_MPU/port.c index 9ff846e..c383c54 100644 --- a/Source/portable/GCC/ARM_CM4_MPU/port.c +++ b/Source/portable/GCC/ARM_CM4_MPU/port.c
@@ -1,6 +1,8 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2025 Arm Limited and/or its affiliates + * <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -57,9 +59,19 @@ #define portNVIC_SYSTICK_CLK ( 0 ) #endif +/* Unprivileged critical sections are not supported when using MPU wrappers + * version 2. Default the option to 0 and reject an explicit value of 1. */ #ifndef configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS - #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." - #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0 + #else + #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #endif +#else + #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) ) + #error configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not supported with MPU wrappers version 2 ( configUSE_MPU_WRAPPERS_V1 == 0 ). + #endif #endif /* Prototype of all Interrupt Service Routines (ISRs). */ @@ -518,7 +530,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being @@ -553,10 +565,14 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -566,14 +582,14 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -591,7 +607,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Store the value of the Link Register before the SVC was raised. * It contains the address of the caller of the System Call entry @@ -644,7 +660,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being @@ -675,10 +691,14 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -688,14 +708,14 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1330,7 +1350,7 @@ } /* Shift the code by one before returning so it can be written directly - * into the the correct bit position of the attribute register. */ + * into the correct bit position of the attribute register. */ return( ulReturnValue << 1UL ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/GCC/ARM_CM4_MPU/portmacro.h b/Source/portable/GCC/ARM_CM4_MPU/portmacro.h index 1ba44d1..6fcc95f 100644 --- a/Source/portable/GCC/ARM_CM4_MPU/portmacro.h +++ b/Source/portable/GCC/ARM_CM4_MPU/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM55/non_secure/mpu_wrappers_v2_asm.c index 9c3e8c7..6dd2be8 100644 --- a/Source/portable/GCC/ARM_CM55/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM55/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/non_secure/port.c b/Source/portable/GCC/ARM_CM55/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM55/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM55/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM55/non_secure/portasm.c b/Source/portable/GCC/ARM_CM55/non_secure/portasm.c index bdee088..6bc070d 100644 --- a/Source/portable/GCC/ARM_CM55/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM55/non_secure/portasm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright 2024 Arm Limited and/or its affiliates * <open-source-office@arm.com> @@ -46,6 +46,16 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #if ( configENABLE_MPU == 1 ) + #if ( configENABLE_PAC == 1 ) + #define SECURE_CONTEXT_OFFSET -36 + #else + #define SECURE_CONTEXT_OFFSET -20 + #endif +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + +#if ( configENABLE_MPU == 1 ) void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */ { @@ -609,13 +619,13 @@ ( " .syntax unified \n" " \n" - " ldr r2, [r0] \n" /* The first item in the TCB is the top of the stack. */ - " ldr r1, [r2] \n" /* The first item on the stack is the task's xSecureContext. */ + " ldr r2, [r0] \n" /* The first item in the TCB is the stored context location. */ + " ldr r1, [r2, %0] \n" /* Read xSecureContext from the task's context. */ " cmp r1, #0 \n" /* Raise svc if task's xSecureContext is not NULL. */ " it ne \n" - " svcne %0 \n" /* Secure context is freed in the supervisor call. */ + " svcne %1 \n" /* Secure context is freed in the supervisor call. */ " bx lr \n" /* Return. */ - ::"i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" + ::"i" ( SECURE_CONTEXT_OFFSET ), "i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/GCC/ARM_CM55/non_secure/portasm.h b/Source/portable/GCC/ARM_CM55/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM55/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM55/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM55/non_secure/portmacro.h index 11a2777..11d6470 100644 --- a/Source/portable/GCC/ARM_CM55/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM55/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM55/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM55/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM55/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM55/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_context.c b/Source/portable/GCC/ARM_CM55/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_context.c +++ b/Source/portable/GCC/ARM_CM55/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_context.h b/Source/portable/GCC/ARM_CM55/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_context.h +++ b/Source/portable/GCC/ARM_CM55/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_context_port.c b/Source/portable/GCC/ARM_CM55/secure/secure_context_port.c index 11d8e1b..ef5cbf7 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_context_port.c +++ b/Source/portable/GCC/ARM_CM55/secure/secure_context_port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_heap.c b/Source/portable/GCC/ARM_CM55/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_heap.c +++ b/Source/portable/GCC/ARM_CM55/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_heap.h b/Source/portable/GCC/ARM_CM55/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_heap.h +++ b/Source/portable/GCC/ARM_CM55/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_init.c b/Source/portable/GCC/ARM_CM55/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_init.c +++ b/Source/portable/GCC/ARM_CM55/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_init.h b/Source/portable/GCC/ARM_CM55/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_init.h +++ b/Source/portable/GCC/ARM_CM55/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55/secure/secure_port_macros.h b/Source/portable/GCC/ARM_CM55/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/GCC/ARM_CM55/secure/secure_port_macros.h +++ b/Source/portable/GCC/ARM_CM55/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.c index 8504ddd..63d1b52 100644 --- a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/port.c b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.c b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.c index 51ec476..fbb00b1 100644 --- a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -134,8 +133,21 @@ ( " .syntax unified \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 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. */ " \n" #if ( configENABLE_PAC == 1 ) @@ -158,6 +170,14 @@ " mov r0, #0 \n" " msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */ " 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 @@ " clrm {r1-r4} \n" /* Clear r1-r4. */ #endif /* configENABLE_PAC */ " \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 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. */ " \n" " mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */ " msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */ " dsb \n" " isb \n" + #if ( configNUMBER_OF_CORES > 1) + " mov r0, r2 \n" /* r0 = ucPortGetCoreID() */ + #endif /* if ( configNUMBER_OF_CORES == 1) */ " bl vTaskSwitchContext \n" " mov r0, #0 \n" /* r0 = 0. */ " msr basepri, r0 \n" /* Enable interrupts. */ " \n" + #if ( configNUMBER_OF_CORES == 1) " ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( 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. */ " \n" #if ( configENABLE_PAC == 1 ) @@ -458,7 +501,16 @@ " 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. */ " 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 ) */ + ); }
diff --git a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.h b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacro.h index 11a2777..11d6470 100644 --- a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM55_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM7/r0p1/port.c b/Source/portable/GCC/ARM_CM7/r0p1/port.c index 7f689ba..b1287ef 100644 --- a/Source/portable/GCC/ARM_CM7/r0p1/port.c +++ b/Source/portable/GCC/ARM_CM7/r0p1/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM7/r0p1/portmacro.h b/Source/portable/GCC/ARM_CM7/r0p1/portmacro.h index eeb95a9..7827664 100644 --- a/Source/portable/GCC/ARM_CM7/r0p1/portmacro.h +++ b/Source/portable/GCC/ARM_CM7/r0p1/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM85/non_secure/mpu_wrappers_v2_asm.c index 9c3e8c7..6dd2be8 100644 --- a/Source/portable/GCC/ARM_CM85/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM85/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/non_secure/port.c b/Source/portable/GCC/ARM_CM85/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM85/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM85/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM85/non_secure/portasm.c b/Source/portable/GCC/ARM_CM85/non_secure/portasm.c index bdee088..6bc070d 100644 --- a/Source/portable/GCC/ARM_CM85/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM85/non_secure/portasm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright 2024 Arm Limited and/or its affiliates * <open-source-office@arm.com> @@ -46,6 +46,16 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #if ( configENABLE_MPU == 1 ) + #if ( configENABLE_PAC == 1 ) + #define SECURE_CONTEXT_OFFSET -36 + #else + #define SECURE_CONTEXT_OFFSET -20 + #endif +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + +#if ( configENABLE_MPU == 1 ) void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */ { @@ -609,13 +619,13 @@ ( " .syntax unified \n" " \n" - " ldr r2, [r0] \n" /* The first item in the TCB is the top of the stack. */ - " ldr r1, [r2] \n" /* The first item on the stack is the task's xSecureContext. */ + " ldr r2, [r0] \n" /* The first item in the TCB is the stored context location. */ + " ldr r1, [r2, %0] \n" /* Read xSecureContext from the task's context. */ " cmp r1, #0 \n" /* Raise svc if task's xSecureContext is not NULL. */ " it ne \n" - " svcne %0 \n" /* Secure context is freed in the supervisor call. */ + " svcne %1 \n" /* Secure context is freed in the supervisor call. */ " bx lr \n" /* Return. */ - ::"i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" + ::"i" ( SECURE_CONTEXT_OFFSET ), "i" ( portSVC_FREE_SECURE_CONTEXT ) : "memory" ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/GCC/ARM_CM85/non_secure/portasm.h b/Source/portable/GCC/ARM_CM85/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM85/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM85/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM85/non_secure/portmacro.h index 3386f52..892228d 100644 --- a/Source/portable/GCC/ARM_CM85/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM85/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM85/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM85/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM85/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM85/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_context.c b/Source/portable/GCC/ARM_CM85/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_context.c +++ b/Source/portable/GCC/ARM_CM85/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_context.h b/Source/portable/GCC/ARM_CM85/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_context.h +++ b/Source/portable/GCC/ARM_CM85/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_context_port.c b/Source/portable/GCC/ARM_CM85/secure/secure_context_port.c index 11d8e1b..ef5cbf7 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_context_port.c +++ b/Source/portable/GCC/ARM_CM85/secure/secure_context_port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_heap.c b/Source/portable/GCC/ARM_CM85/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_heap.c +++ b/Source/portable/GCC/ARM_CM85/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_heap.h b/Source/portable/GCC/ARM_CM85/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_heap.h +++ b/Source/portable/GCC/ARM_CM85/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_init.c b/Source/portable/GCC/ARM_CM85/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_init.c +++ b/Source/portable/GCC/ARM_CM85/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_init.h b/Source/portable/GCC/ARM_CM85/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_init.h +++ b/Source/portable/GCC/ARM_CM85/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85/secure/secure_port_macros.h b/Source/portable/GCC/ARM_CM85/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/GCC/ARM_CM85/secure/secure_port_macros.h +++ b/Source/portable/GCC/ARM_CM85/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.c b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.c index 8504ddd..63d1b52 100644 --- a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.c +++ b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/port.c b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/port.c +++ b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.c b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.c index 51ec476..fbb00b1 100644 --- a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.c +++ b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -134,8 +133,21 @@ ( " .syntax unified \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 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. */ " \n" #if ( configENABLE_PAC == 1 ) @@ -158,6 +170,14 @@ " mov r0, #0 \n" " msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */ " 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 @@ " clrm {r1-r4} \n" /* Clear r1-r4. */ #endif /* configENABLE_PAC */ " \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 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. */ " \n" " mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */ " msr basepri, r0 \n" /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */ " dsb \n" " isb \n" + #if ( configNUMBER_OF_CORES > 1) + " mov r0, r2 \n" /* r0 = ucPortGetCoreID() */ + #endif /* if ( configNUMBER_OF_CORES == 1) */ " bl vTaskSwitchContext \n" " mov r0, #0 \n" /* r0 = 0. */ " msr basepri, r0 \n" /* Enable interrupts. */ " \n" + #if ( configNUMBER_OF_CORES == 1) " ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( 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. */ " \n" #if ( configENABLE_PAC == 1 ) @@ -458,7 +501,16 @@ " 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. */ " 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 ) */ + ); }
diff --git a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.h b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.h +++ b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacro.h b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacro.h index 3386f52..892228d 100644 --- a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacro.h +++ b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __attribute__( ( used ) ) +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacrocommon.h b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/GCC/ARM_CM85_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CA9/port.c b/Source/portable/IAR/ARM_CA9/port.c index 9940833..762aab7 100644 --- a/Source/portable/IAR/ARM_CA9/port.c +++ b/Source/portable/IAR/ARM_CA9/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CA9/portASM.h b/Source/portable/IAR/ARM_CA9/portASM.h index 2855a0c..9902404 100644 --- a/Source/portable/IAR/ARM_CA9/portASM.h +++ b/Source/portable/IAR/ARM_CA9/portASM.h
@@ -1,5 +1,5 @@ ;/* -; * FreeRTOS Kernel V11.2.0 +; * FreeRTOS Kernel V11.3.1 ; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. ; * ; * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CA9/portASM.s b/Source/portable/IAR/ARM_CA9/portASM.s index ebb86e9..95ca33b 100644 --- a/Source/portable/IAR/ARM_CA9/portASM.s +++ b/Source/portable/IAR/ARM_CA9/portASM.s
@@ -1,5 +1,5 @@ ;/* -; * FreeRTOS Kernel V11.2.0 +; * FreeRTOS Kernel V11.3.1 ; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. ; * ; * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CA9/portmacro.h b/Source/portable/IAR/ARM_CA9/portmacro.h index f218e60..a12fa9a 100644 --- a/Source/portable/IAR/ARM_CA9/portmacro.h +++ b/Source/portable/IAR/ARM_CA9/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM0/port.c b/Source/portable/IAR/ARM_CM0/port.c index 6f7c899..06d0968 100644 --- a/Source/portable/IAR/ARM_CM0/port.c +++ b/Source/portable/IAR/ARM_CM0/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM0/portasm.s b/Source/portable/IAR/ARM_CM0/portasm.s index bc33363..afba1f4 100644 --- a/Source/portable/IAR/ARM_CM0/portasm.s +++ b/Source/portable/IAR/ARM_CM0/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM0/portmacro.h b/Source/portable/IAR/ARM_CM0/portmacro.h index e384e59..82ec004 100644 --- a/Source/portable/IAR/ARM_CM0/portmacro.h +++ b/Source/portable/IAR/ARM_CM0/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM23/non_secure/mpu_wrappers_v2_asm.S index eaafcee..39695d6 100644 --- a/Source/portable/IAR/ARM_CM23/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM23/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/non_secure/port.c b/Source/portable/IAR/ARM_CM23/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM23/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM23/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM23/non_secure/portasm.h b/Source/portable/IAR/ARM_CM23/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM23/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM23/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/non_secure/portasm.s b/Source/portable/IAR/ARM_CM23/non_secure/portasm.s index 6b25588..137d464 100644 --- a/Source/portable/IAR/ARM_CM23/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM23/non_secure/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -40,6 +40,12 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#if ( configENABLE_MPU == 1 ) + #define SECURE_CONTEXT_OFFSET -20 +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + EXTERN pxCurrentTCB EXTERN xSecureContext @@ -512,8 +518,9 @@ /*-----------------------------------------------------------*/ vPortFreeSecureContext: - ldr r2, [r0] /* The first item in the TCB is the top of the stack. */ - ldr r1, [r2] /* The first item on the stack is the task's xSecureContext. */ + ldr r2, [r0] /* The first item in the TCB is the stored context location. */ + adds r2, r2, #SECURE_CONTEXT_OFFSET /* r2 = r2 + SECURE_CONTEXT_OFFSET. */ + ldr r1, [r2] /* Read xSecureContext from the task's context. */ cmp r1, #0 /* Raise svc if task's xSecureContext is not NULL. */ bne free_secure_context /* Branch if r1 != 0. */ bx lr /* There is no secure context (xSecureContext is NULL). */
diff --git a/Source/portable/IAR/ARM_CM23/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM23/non_secure/portmacro.h index 6cf50c5..4fb83e0 100644 --- a/Source/portable/IAR/ARM_CM23/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM23/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 0 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM23/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM23/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM23/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM23/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_context.c b/Source/portable/IAR/ARM_CM23/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_context.c +++ b/Source/portable/IAR/ARM_CM23/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_context.h b/Source/portable/IAR/ARM_CM23/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_context.h +++ b/Source/portable/IAR/ARM_CM23/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_context_port_asm.s b/Source/portable/IAR/ARM_CM23/secure/secure_context_port_asm.s index e3ff975..0a52ad1 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_context_port_asm.s +++ b/Source/portable/IAR/ARM_CM23/secure/secure_context_port_asm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_heap.c b/Source/portable/IAR/ARM_CM23/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_heap.c +++ b/Source/portable/IAR/ARM_CM23/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_heap.h b/Source/portable/IAR/ARM_CM23/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_heap.h +++ b/Source/portable/IAR/ARM_CM23/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_init.c b/Source/portable/IAR/ARM_CM23/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_init.c +++ b/Source/portable/IAR/ARM_CM23/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_init.h b/Source/portable/IAR/ARM_CM23/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_init.h +++ b/Source/portable/IAR/ARM_CM23/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23/secure/secure_port_macros.h b/Source/portable/IAR/ARM_CM23/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/IAR/ARM_CM23/secure/secure_port_macros.h +++ b/Source/portable/IAR/ARM_CM23/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.S index eaafcee..39695d6 100644 --- a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/port.c b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.h b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.s b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.s index 200751b..03e8a71 100644 --- a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacro.h index 6cf50c5..4fb83e0 100644 --- a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 0 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM23_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM3/port.c b/Source/portable/IAR/ARM_CM3/port.c index e706a6d..efd4e53 100644 --- a/Source/portable/IAR/ARM_CM3/port.c +++ b/Source/portable/IAR/ARM_CM3/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM3/portasm.s b/Source/portable/IAR/ARM_CM3/portasm.s index 0344b9c..948da86 100644 --- a/Source/portable/IAR/ARM_CM3/portasm.s +++ b/Source/portable/IAR/ARM_CM3/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM3/portmacro.h b/Source/portable/IAR/ARM_CM3/portmacro.h index 26b976a..c4a076e 100644 --- a/Source/portable/IAR/ARM_CM3/portmacro.h +++ b/Source/portable/IAR/ARM_CM3/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM33/non_secure/mpu_wrappers_v2_asm.S index 68192e4..c8df7ec 100644 --- a/Source/portable/IAR/ARM_CM33/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM33/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/non_secure/port.c b/Source/portable/IAR/ARM_CM33/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM33/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM33/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM33/non_secure/portasm.h b/Source/portable/IAR/ARM_CM33/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM33/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM33/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/non_secure/portasm.s b/Source/portable/IAR/ARM_CM33/non_secure/portasm.s index b5c91e5..c31d9ed 100644 --- a/Source/portable/IAR/ARM_CM33/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM33/non_secure/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright 2024 Arm Limited and/or its affiliates * <open-source-office@arm.com> @@ -41,6 +41,16 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#if ( configENABLE_MPU == 1 ) + #if ( configENABLE_PAC == 1 ) + #define SECURE_CONTEXT_OFFSET -36 + #else + #define SECURE_CONTEXT_OFFSET -20 + #endif +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + EXTERN pxCurrentTCB EXTERN xSecureContext EXTERN vTaskSwitchContext @@ -532,8 +542,8 @@ vPortFreeSecureContext: /* r0 = uint32_t *pulTCB. */ - ldr r2, [r0] /* The first item in the TCB is the top of the stack. */ - ldr r1, [r2] /* The first item on the stack is the task's xSecureContext. */ + ldr r2, [r0] /* The first item in the TCB is the stored context location. */ + ldr r1, [r2, #SECURE_CONTEXT_OFFSET] /* Read xSecureContext from the task's context. */ cmp r1, #0 /* Raise svc if task's xSecureContext is not NULL. */ it ne svcne 101 /* Secure context is freed in the supervisor call. portSVC_FREE_SECURE_CONTEXT = 101. */
diff --git a/Source/portable/IAR/ARM_CM33/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM33/non_secure/portmacro.h index df7888d..89a3243 100644 --- a/Source/portable/IAR/ARM_CM33/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM33/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM33/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM33/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM33/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM33/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_context.c b/Source/portable/IAR/ARM_CM33/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_context.c +++ b/Source/portable/IAR/ARM_CM33/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_context.h b/Source/portable/IAR/ARM_CM33/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_context.h +++ b/Source/portable/IAR/ARM_CM33/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_context_port_asm.s b/Source/portable/IAR/ARM_CM33/secure/secure_context_port_asm.s index 5cc070e..519c64b 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_context_port_asm.s +++ b/Source/portable/IAR/ARM_CM33/secure/secure_context_port_asm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_heap.c b/Source/portable/IAR/ARM_CM33/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_heap.c +++ b/Source/portable/IAR/ARM_CM33/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_heap.h b/Source/portable/IAR/ARM_CM33/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_heap.h +++ b/Source/portable/IAR/ARM_CM33/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_init.c b/Source/portable/IAR/ARM_CM33/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_init.c +++ b/Source/portable/IAR/ARM_CM33/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_init.h b/Source/portable/IAR/ARM_CM33/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_init.h +++ b/Source/portable/IAR/ARM_CM33/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33/secure/secure_port_macros.h b/Source/portable/IAR/ARM_CM33/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/IAR/ARM_CM33/secure/secure_port_macros.h +++ b/Source/portable/IAR/ARM_CM33/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.S index 68192e4..c8df7ec 100644 --- a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/port.c b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.h b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.s b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.s index 8092255..8de575d 100644 --- a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portasm.s
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -41,7 +40,15 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#ifndef configNUMBER_OF_CORES + #define configNUMBER_OF_CORES 1 +#endif + +#if ( configNUMBER_OF_CORES == 1) EXTERN pxCurrentTCB +#else /* if ( configNUMBER_OF_CORES == 1) */ + EXTERN pxCurrentTCBs +#endif EXTERN vTaskSwitchContext EXTERN vPortSVCHandler_C #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) @@ -169,8 +176,15 @@ #else /* configENABLE_MPU */ vRestoreContextOfFirstTask: +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ #if ( configENABLE_PAC == 1 ) @@ -193,6 +207,13 @@ mov r0, #0 msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */ 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 */ /*-----------------------------------------------------------*/ @@ -377,20 +398,37 @@ clrm {r1-r4} /* Clear r1-r4. */ #endif /* configENABLE_PAC */ +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */ dsb isb + #if ( configNUMBER_OF_CORES > 1) + mov r0, r2 /* r0 = ucPortGetCoreID() */ + #endif /* if ( configNUMBER_OF_CORES == 1) */ bl vTaskSwitchContext mov r0, #0 /* r0 = 0. */ msr basepri, r0 /* Enable interrupts. */ +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ #if ( configENABLE_PAC == 1 ) @@ -413,6 +451,13 @@ msr psplim, r2 /* Restore the PSPLIM register value for the task. */ msr psp, r0 /* Remember the new top of stack for the task. */ 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 */ /*-----------------------------------------------------------*/
diff --git a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacro.h index df7888d..db025b5 100644 --- a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -52,6 +53,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 0 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 1 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM33_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM4F/port.c b/Source/portable/IAR/ARM_CM4F/port.c index a863cac..dfeed7a 100644 --- a/Source/portable/IAR/ARM_CM4F/port.c +++ b/Source/portable/IAR/ARM_CM4F/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM4F/portasm.s b/Source/portable/IAR/ARM_CM4F/portasm.s index 627b1bf..cb10f41 100644 --- a/Source/portable/IAR/ARM_CM4F/portasm.s +++ b/Source/portable/IAR/ARM_CM4F/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM4F/portmacro.h b/Source/portable/IAR/ARM_CM4F/portmacro.h index 2bc2281..9ad246e 100644 --- a/Source/portable/IAR/ARM_CM4F/portmacro.h +++ b/Source/portable/IAR/ARM_CM4F/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM4_MPU/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM4_MPU/mpu_wrappers_v2_asm.S index 310636b..5fae1d3 100644 --- a/Source/portable/IAR/ARM_CM4_MPU/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM4_MPU/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM4_MPU/port.c b/Source/portable/IAR/ARM_CM4_MPU/port.c index 08125a2..ac761c4 100644 --- a/Source/portable/IAR/ARM_CM4_MPU/port.c +++ b/Source/portable/IAR/ARM_CM4_MPU/port.c
@@ -1,6 +1,8 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2025 Arm Limited and/or its affiliates + * <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -64,9 +66,19 @@ #define portNVIC_SYSTICK_CLK_BIT ( 0 ) #endif +/* Unprivileged critical sections are not supported when using MPU wrappers + * version 2. Default the option to 0 and reject an explicit value of 1. */ #ifndef configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS - #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." - #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0 + #else + #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #endif +#else + #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) ) + #error configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not supported with MPU wrappers version 2 ( configUSE_MPU_WRAPPERS_V1 == 0 ). + #endif #endif /* Prototype of all Interrupt Service Routines (ISRs). */ @@ -459,7 +471,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being @@ -494,10 +506,14 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -507,14 +523,14 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -532,7 +548,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Store the value of the Link Register before the SVC was raised. * It contains the address of the caller of the System Call entry @@ -586,7 +602,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) /* Declaration when these variable are defined in code instead of being @@ -617,10 +633,14 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -630,14 +650,14 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1119,7 +1139,7 @@ } /* Shift the code by one before returning so it can be written directly - * into the the correct bit position of the attribute register. */ + * into the correct bit position of the attribute register. */ return( ulReturnValue << 1UL ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/IAR/ARM_CM4_MPU/portasm.s b/Source/portable/IAR/ARM_CM4_MPU/portasm.s index 523422a..6fb8545 100644 --- a/Source/portable/IAR/ARM_CM4_MPU/portasm.s +++ b/Source/portable/IAR/ARM_CM4_MPU/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM4_MPU/portmacro.h b/Source/portable/IAR/ARM_CM4_MPU/portmacro.h index 12e35b6..dd77194 100644 --- a/Source/portable/IAR/ARM_CM4_MPU/portmacro.h +++ b/Source/portable/IAR/ARM_CM4_MPU/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM55/non_secure/mpu_wrappers_v2_asm.S index 68192e4..c8df7ec 100644 --- a/Source/portable/IAR/ARM_CM55/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM55/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/non_secure/port.c b/Source/portable/IAR/ARM_CM55/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM55/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM55/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM55/non_secure/portasm.h b/Source/portable/IAR/ARM_CM55/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM55/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM55/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/non_secure/portasm.s b/Source/portable/IAR/ARM_CM55/non_secure/portasm.s index b5c91e5..c31d9ed 100644 --- a/Source/portable/IAR/ARM_CM55/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM55/non_secure/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright 2024 Arm Limited and/or its affiliates * <open-source-office@arm.com> @@ -41,6 +41,16 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#if ( configENABLE_MPU == 1 ) + #if ( configENABLE_PAC == 1 ) + #define SECURE_CONTEXT_OFFSET -36 + #else + #define SECURE_CONTEXT_OFFSET -20 + #endif +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + EXTERN pxCurrentTCB EXTERN xSecureContext EXTERN vTaskSwitchContext @@ -532,8 +542,8 @@ vPortFreeSecureContext: /* r0 = uint32_t *pulTCB. */ - ldr r2, [r0] /* The first item in the TCB is the top of the stack. */ - ldr r1, [r2] /* The first item on the stack is the task's xSecureContext. */ + ldr r2, [r0] /* The first item in the TCB is the stored context location. */ + ldr r1, [r2, #SECURE_CONTEXT_OFFSET] /* Read xSecureContext from the task's context. */ cmp r1, #0 /* Raise svc if task's xSecureContext is not NULL. */ it ne svcne 101 /* Secure context is freed in the supervisor call. portSVC_FREE_SECURE_CONTEXT = 101. */
diff --git a/Source/portable/IAR/ARM_CM55/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM55/non_secure/portmacro.h index 0526455..0a4d223 100644 --- a/Source/portable/IAR/ARM_CM55/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM55/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM55/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM55/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM55/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM55/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_context.c b/Source/portable/IAR/ARM_CM55/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_context.c +++ b/Source/portable/IAR/ARM_CM55/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_context.h b/Source/portable/IAR/ARM_CM55/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_context.h +++ b/Source/portable/IAR/ARM_CM55/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_context_port_asm.s b/Source/portable/IAR/ARM_CM55/secure/secure_context_port_asm.s index 5cc070e..519c64b 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_context_port_asm.s +++ b/Source/portable/IAR/ARM_CM55/secure/secure_context_port_asm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_heap.c b/Source/portable/IAR/ARM_CM55/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_heap.c +++ b/Source/portable/IAR/ARM_CM55/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_heap.h b/Source/portable/IAR/ARM_CM55/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_heap.h +++ b/Source/portable/IAR/ARM_CM55/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_init.c b/Source/portable/IAR/ARM_CM55/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_init.c +++ b/Source/portable/IAR/ARM_CM55/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_init.h b/Source/portable/IAR/ARM_CM55/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_init.h +++ b/Source/portable/IAR/ARM_CM55/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55/secure/secure_port_macros.h b/Source/portable/IAR/ARM_CM55/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/IAR/ARM_CM55/secure/secure_port_macros.h +++ b/Source/portable/IAR/ARM_CM55/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.S index 68192e4..c8df7ec 100644 --- a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/port.c b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.h b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.s b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.s index 8092255..8de575d 100644 --- a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portasm.s
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -41,7 +40,15 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#ifndef configNUMBER_OF_CORES + #define configNUMBER_OF_CORES 1 +#endif + +#if ( configNUMBER_OF_CORES == 1) EXTERN pxCurrentTCB +#else /* if ( configNUMBER_OF_CORES == 1) */ + EXTERN pxCurrentTCBs +#endif EXTERN vTaskSwitchContext EXTERN vPortSVCHandler_C #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) @@ -169,8 +176,15 @@ #else /* configENABLE_MPU */ vRestoreContextOfFirstTask: +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ #if ( configENABLE_PAC == 1 ) @@ -193,6 +207,13 @@ mov r0, #0 msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */ 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 */ /*-----------------------------------------------------------*/ @@ -377,20 +398,37 @@ clrm {r1-r4} /* Clear r1-r4. */ #endif /* configENABLE_PAC */ +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */ dsb isb + #if ( configNUMBER_OF_CORES > 1) + mov r0, r2 /* r0 = ucPortGetCoreID() */ + #endif /* if ( configNUMBER_OF_CORES == 1) */ bl vTaskSwitchContext mov r0, #0 /* r0 = 0. */ msr basepri, r0 /* Enable interrupts. */ +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ #if ( configENABLE_PAC == 1 ) @@ -413,6 +451,13 @@ msr psplim, r2 /* Restore the PSPLIM register value for the task. */ msr psp, r0 /* Remember the new top of stack for the task. */ 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 */ /*-----------------------------------------------------------*/
diff --git a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacro.h index 0526455..0a4d223 100644 --- a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM55_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM7/r0p1/port.c b/Source/portable/IAR/ARM_CM7/r0p1/port.c index 924e27e..3b2e734 100644 --- a/Source/portable/IAR/ARM_CM7/r0p1/port.c +++ b/Source/portable/IAR/ARM_CM7/r0p1/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM7/r0p1/portasm.s b/Source/portable/IAR/ARM_CM7/r0p1/portasm.s index 4d4ffaf..32a3fd9 100644 --- a/Source/portable/IAR/ARM_CM7/r0p1/portasm.s +++ b/Source/portable/IAR/ARM_CM7/r0p1/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM7/r0p1/portmacro.h b/Source/portable/IAR/ARM_CM7/r0p1/portmacro.h index 4fa219e..507cc8b 100644 --- a/Source/portable/IAR/ARM_CM7/r0p1/portmacro.h +++ b/Source/portable/IAR/ARM_CM7/r0p1/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM85/non_secure/mpu_wrappers_v2_asm.S index 68192e4..c8df7ec 100644 --- a/Source/portable/IAR/ARM_CM85/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM85/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/non_secure/port.c b/Source/portable/IAR/ARM_CM85/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM85/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM85/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM85/non_secure/portasm.h b/Source/portable/IAR/ARM_CM85/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM85/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM85/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/non_secure/portasm.s b/Source/portable/IAR/ARM_CM85/non_secure/portasm.s index b5c91e5..c31d9ed 100644 --- a/Source/portable/IAR/ARM_CM85/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM85/non_secure/portasm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright 2024 Arm Limited and/or its affiliates * <open-source-office@arm.com> @@ -41,6 +41,16 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#if ( configENABLE_MPU == 1 ) + #if ( configENABLE_PAC == 1 ) + #define SECURE_CONTEXT_OFFSET -36 + #else + #define SECURE_CONTEXT_OFFSET -20 + #endif +#else + #define SECURE_CONTEXT_OFFSET 0 +#endif + EXTERN pxCurrentTCB EXTERN xSecureContext EXTERN vTaskSwitchContext @@ -532,8 +542,8 @@ vPortFreeSecureContext: /* r0 = uint32_t *pulTCB. */ - ldr r2, [r0] /* The first item in the TCB is the top of the stack. */ - ldr r1, [r2] /* The first item on the stack is the task's xSecureContext. */ + ldr r2, [r0] /* The first item in the TCB is the stored context location. */ + ldr r1, [r2, #SECURE_CONTEXT_OFFSET] /* Read xSecureContext from the task's context. */ cmp r1, #0 /* Raise svc if task's xSecureContext is not NULL. */ it ne svcne 101 /* Secure context is freed in the supervisor call. portSVC_FREE_SECURE_CONTEXT = 101. */
diff --git a/Source/portable/IAR/ARM_CM85/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM85/non_secure/portmacro.h index 2f1676c..4b2faaf 100644 --- a/Source/portable/IAR/ARM_CM85/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM85/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM85/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM85/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM85/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM85/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_context.c b/Source/portable/IAR/ARM_CM85/secure/secure_context.c index 62bcfa1..2dae022 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_context.c +++ b/Source/portable/IAR/ARM_CM85/secure/secure_context.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -213,8 +213,19 @@ /* Were we able to get a free context? */ if( ulSecureContextIndex < secureconfigMAX_SECURE_CONTEXTS ) { - /* Allocate the stack space. */ - pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + /* Allocate the stack space if possible. */ + if( ( ulSecureStackSize < securecontextSTACK_SEAL_SIZE ) || + ( ulSecureStackSize > ( UINT32_MAX - securecontextSTACK_SEAL_SIZE ) ) ) + { + /* Reject stacks that are too small (the CONTROL word would be + * written before the allocation, corrupting the secure heap) + * and sizes that would overflow when the seal size is added. */ + pucStackMemory = NULL; + } + else + { + pucStackMemory = pvPortMalloc( ulSecureStackSize + securecontextSTACK_SEAL_SIZE ); + } if( pucStackMemory != NULL ) { @@ -279,9 +290,12 @@ void * pvTaskHandle ) { uint32_t ulIPSR, ulSecureContextIndex; + uint8_t * pucStackLimit; - /* Read the Interrupt Program Status Register (IPSR) value. */ + /* Read the Interrupt Program Status Register (IPSR) and Process Stack Limit + * Register (PSPLIM) value. */ secureportREAD_IPSR( ulIPSR ); + secureportREAD_PSPLIM( pucStackLimit ); /* Do nothing if the processor is running in the Thread Mode. IPSR is zero * when the processor is running in the Thread Mode. */ @@ -293,8 +307,14 @@ ulSecureContextIndex = xSecureContextHandle - 1UL; /* Ensure that the secure context being deleted is associated with - * the task. */ - if( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) + * the task and is NOT the currently-loaded context. Freeing a + * context whose stack is currently loaded in PSPLIM would leave the + * running task referencing freed secure memory (use-after-free). + * pvTaskHandle is supplied by the non-secure side and is untrusted, + * so it is used only as an additional ownership match, not as + * authority. */ + if( ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) && + ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit != pucStackLimit ) ) { /* Free the stack space. */ vPortFree( xSecureContexts[ ulSecureContextIndex ].pucStackLimit ); @@ -342,7 +362,7 @@ secureportREAD_PSPLIM( pucStackLimit ); - /* Ensure that task's context is loaded and the task is saving it's own + /* Ensure that task's context is loaded and the task is saving its own * context. */ if( ( xSecureContexts[ ulSecureContextIndex ].pucStackLimit == pucStackLimit ) && ( xSecureContexts[ ulSecureContextIndex ].pvTaskHandle == pvTaskHandle ) )
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_context.h b/Source/portable/IAR/ARM_CM85/secure/secure_context.h index 8b93857..51dd823 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_context.h +++ b/Source/portable/IAR/ARM_CM85/secure/secure_context.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_context_port_asm.s b/Source/portable/IAR/ARM_CM85/secure/secure_context_port_asm.s index 5cc070e..519c64b 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_context_port_asm.s +++ b/Source/portable/IAR/ARM_CM85/secure/secure_context_port_asm.s
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_heap.c b/Source/portable/IAR/ARM_CM85/secure/secure_heap.c index b0e83b4..58226bf 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_heap.c +++ b/Source/portable/IAR/ARM_CM85/secure/secure_heap.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_heap.h b/Source/portable/IAR/ARM_CM85/secure/secure_heap.h index 61a96da..906fa24 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_heap.h +++ b/Source/portable/IAR/ARM_CM85/secure/secure_heap.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_init.c b/Source/portable/IAR/ARM_CM85/secure/secure_init.c index f7f7e67..6996692 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_init.c +++ b/Source/portable/IAR/ARM_CM85/secure/secure_init.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_init.h b/Source/portable/IAR/ARM_CM85/secure/secure_init.h index 46ffbd9..4e7bd40 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_init.h +++ b/Source/portable/IAR/ARM_CM85/secure/secure_init.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85/secure/secure_port_macros.h b/Source/portable/IAR/ARM_CM85/secure/secure_port_macros.h index 34494e1..72774eb 100644 --- a/Source/portable/IAR/ARM_CM85/secure/secure_port_macros.h +++ b/Source/portable/IAR/ARM_CM85/secure/secure_port_macros.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.S b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.S index 68192e4..c8df7ec 100644 --- a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.S +++ b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/mpu_wrappers_v2_asm.S
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/port.c b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/port.c index f16a343..007150c 100644 --- a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/port.c +++ b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/port.c
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024-2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -145,13 +144,13 @@ /** * @brief Constants required to manipulate the FPU. */ -#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ +#define portCPACR ( ( volatile uint32_t * ) 0xe000ed88 ) /* Coprocessor Access Control Register. */ #define portCPACR_CP10_VALUE ( 3UL ) #define portCPACR_CP11_VALUE portCPACR_CP10_VALUE #define portCPACR_CP10_POS ( 20UL ) #define portCPACR_CP11_POS ( 22UL ) -#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ +#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating Point Context Control Register. */ #define portFPCCR_ASPEN_POS ( 31UL ) #define portFPCCR_ASPEN_MASK ( 1UL << portFPCCR_ASPEN_POS ) #define portFPCCR_LSPEN_POS ( 30UL ) @@ -188,8 +187,8 @@ #define portMPU_MAIR0_REG ( *( ( volatile uint32_t * ) 0xe000edc0 ) ) #define portMPU_MAIR1_REG ( *( ( volatile uint32_t * ) 0xe000edc4 ) ) -#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ -#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RBAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ +#define portMPU_RLAR_ADDRESS_MASK ( 0xffffffe0 ) /* Must be 32-byte aligned. */ #define portMPU_RBAR_ACCESS_PERMISSIONS_MASK ( 3UL << 1UL ) @@ -230,8 +229,8 @@ #if ( portARMV8M_MINOR_VERSION >= 1 ) -/* Enable Privileged eXecute Never MPU attribute for the selected memory - * region. */ + /* Enable Privileged eXecute Never MPU attribute for the selected memory + * region. */ #define portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER ( 1UL << 4UL ) #endif /* portARMV8M_MINOR_VERSION >= 1 */ @@ -241,9 +240,6 @@ /* Enable MPU. */ #define portMPU_ENABLE_BIT ( 1UL << 0UL ) -/* Expected value of the portMPU_TYPE register. */ -#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL ) - /* Extract first address of the MPU region as encoded in the * RBAR (Region Base Address Register) value. */ #define portEXTRACT_FIRST_ADDRESS_FROM_RBAR( rbar ) \ @@ -291,37 +287,37 @@ #if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF FD - * 1111 1111 1111 1111 1111 1111 1111 1101 - * - * Bit[6] - 1 --> The exception was taken from the Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 1 --> The exception was taken to the Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF FD + * 1111 1111 1111 1111 1111 1111 1111 1101 + * + * Bit[6] - 1 --> The exception was taken from the Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 1 --> The exception was taken to the Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xfffffffd ) #else -/** - * @brief Initial EXC_RETURN value. - * - * FF FF FF BC - * 1111 1111 1111 1111 1111 1111 1011 1100 - * - * Bit[6] - 0 --> The exception was taken from the Non-Secure state. - * Bit[5] - 1 --> Do not skip stacking of additional state context. - * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. - * Bit[3] - 1 --> Return to the Thread mode. - * Bit[2] - 1 --> Restore registers from the process stack. - * Bit[1] - 0 --> Reserved, 0. - * Bit[0] - 0 --> The exception was taken to the Non-Secure state. - */ + /** + * @brief Initial EXC_RETURN value. + * + * FF FF FF BC + * 1111 1111 1111 1111 1111 1111 1011 1100 + * + * Bit[6] - 0 --> The exception was taken from the Non-Secure state. + * Bit[5] - 1 --> Do not skip stacking of additional state context. + * Bit[4] - 1 --> The PE did not allocate space on the stack for FP context. + * Bit[3] - 1 --> Return to the Thread mode. + * Bit[2] - 1 --> Restore registers from the process stack. + * Bit[1] - 0 --> Reserved, 0. + * Bit[0] - 0 --> The exception was taken to the Non-Secure state. + */ #define portINITIAL_EXC_RETURN ( 0xffffffbc ) #endif /* configRUN_FREERTOS_SECURE_ONLY */ @@ -401,50 +397,54 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Extract MPU region's access permissions from the Region Base Address - * Register (RBAR) value. - * - * @param ulRBARValue RBAR value for the MPU region. - * - * @return uint32_t Access permissions. - */ + /** + * @brief Extract MPU region's access permissions from the Region Base Address + * Register (RBAR) value. + * + * @param ulRBARValue RBAR value for the MPU region. + * + * @return uint32_t Access permissions. + */ static uint32_t prvGetRegionAccessPermissions( uint32_t ulRBARValue ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU == 1 && configUSE_MPU_WRAPPERS_V1 == 0 */ #if ( configENABLE_MPU == 1 ) -/** - * @brief Setup the Memory Protection Unit (MPU). - */ + /** + * @brief Setup the Memory Protection Unit (MPU). + */ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_MPU */ #if ( configENABLE_FPU == 1 ) -/** - * @brief Setup the Floating Point Unit (FPU). - */ + /** + * @brief Setup the Floating Point Unit (FPU). + */ static void prvSetupFPU( void ) PRIVILEGED_FUNCTION; #endif /* configENABLE_FPU */ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) -/** - * @brief Configures PACBTI features. - * - * This function configures the Pointer Authentication, and Branch Target - * Identification security features as per the user configuration. It returns - * the value of the special purpose CONTROL register accordingly, and optionally - * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M - * architecture based) target supports PACBTI security feature. - * - * @param xWriteControlRegister Used to control whether the special purpose - * CONTROL register should be updated or not. - * - * @return CONTROL register value according to the configured PACBTI option. - */ - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ); + /** + * @brief Configures PACBTI features. + * + * This function configures the Pointer Authentication, and Branch Target + * Identification security features as per the user configuration. It returns + * the value of the special purpose CONTROL register accordingly, and optionally + * updates the CONTROL register value. Currently, only Cortex-M85 (ARMv8.1-M + * architecture based) target supports PACBTI security feature. + * + * @param xWriteControlRegister Used to control whether the special purpose + * CONTROL register should be updated or not. + * + * @return CONTROL register value according to the configured PACBTI option. + */ + #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 */ @@ -491,14 +491,14 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the system call stack so that upon returning from - * SVC, the system call stack is used. - * - * @param pulTaskStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - * @param ucSystemCallNumber The system call number of the system call. - */ + /** + * @brief Sets up the system call stack so that upon returning from + * SVC, the system call stack is used. + * + * @param pulTaskStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + * @param ucSystemCallNumber The system call number of the system call. + */ void vSystemCallEnter( uint32_t * pulTaskStack, uint32_t ulLR, uint8_t ucSystemCallNumber ) PRIVILEGED_FUNCTION; @@ -507,22 +507,22 @@ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Raise SVC for exiting from a system call. - */ + /** + * @brief Raise SVC for exiting from a system call. + */ void vRequestSystemCallExit( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief Sets up the task stack so that upon returning from - * SVC, the task stack is used again. - * - * @param pulSystemCallStack The current SP when the SVC was raised. - * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. - */ + /** + * @brief Sets up the task stack so that upon returning from + * SVC, the task stack is used again. + * + * @param pulSystemCallStack The current SP when the SVC was raised. + * @param ulLR The value of Link Register (EXC_RETURN) in the SVC handler. + */ void vSystemCallExit( uint32_t * pulSystemCallStack, uint32_t ulLR ) PRIVILEGED_FUNCTION; @@ -530,21 +530,38 @@ #if ( configENABLE_MPU == 1 ) -/** - * @brief Checks whether or not the calling task is privileged. - * - * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. - */ + /** + * @brief Checks whether or not the calling task is privileged. + * + * @return pdTRUE if the calling task is privileged, pdFALSE otherwise. + */ BaseType_t xPortIsTaskPrivileged( void ) PRIVILEGED_FUNCTION; #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 ) */ + +/** + * @brief Configures interrupt priorities. + */ +void vPortConfigureInterruptPriorities( void ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) -/** - * @brief This variable is set to pdTRUE when the scheduler is started. - */ + /** + * @brief This variable is set to pdTRUE when the scheduler is started. + */ PRIVILEGED_DATA static BaseType_t xSchedulerRunning = pdFALSE; #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ @@ -553,14 +570,22 @@ * @brief Each task maintains its own interrupt status in the critical nesting * 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 ) -/** - * @brief Saved as part of the task context to indicate which context the - * task is using on the secure side. - */ + /** + * @brief Saved as part of the task context to indicate which context the + * task is using on the secure side. + */ PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; #endif /* configENABLE_TRUSTZONE */ @@ -579,21 +604,21 @@ #if ( configUSE_TICKLESS_IDLE == 1 ) -/** - * @brief The number of SysTick increments that make up one tick period. - */ + /** + * @brief The number of SysTick increments that make up one tick period. + */ PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0; -/** - * @brief The maximum number of tick periods that can be suppressed is - * limited by the 24 bit resolution of the SysTick timer. - */ + /** + * @brief The maximum number of tick periods that can be suppressed is + * limited by the 24 bit resolution of the SysTick timer. + */ PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0; -/** - * @brief Compensate for the CPU cycles that pass while the SysTick is - * stopped (low power functionality only). - */ + /** + * @brief Compensate for the CPU cycles that pass while the SysTick is + * stopped (low power functionality only). + */ PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ @@ -856,7 +881,11 @@ * should instead call vTaskDelete( NULL ). Artificially force an assert() * to be triggered if configASSERT() is defined, then stop here so * 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(); while( ulDummy == 0 ) @@ -925,64 +954,57 @@ /* The only permitted number of regions are 8 or 16. */ configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) ); - /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */ - configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ); + /* MAIR0 - Index 0. */ + portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); + /* MAIR0 - Index 1. */ + portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); - /* Check that the MPU is present. */ - if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) - { - /* MAIR0 - Index 0. */ - portMPU_MAIR0_REG |= ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); - /* MAIR0 - Index 1. */ - portMPU_MAIR0_REG |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK ); + /* Setup privileged flash as Read Only so that privileged tasks can + * read it but not modify. */ + portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup privileged flash as Read Only so that privileged tasks can - * read it but not modify. */ - portMPU_RNR_REG = portPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_functions_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged flash as Read Only by both privileged and + * unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged flash as Read Only by both privileged and - * unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_FLASH_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __unprivileged_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __unprivileged_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup unprivileged syscalls flash as Read Only by both privileged + * and unprivileged tasks. All tasks can read it but no-one can modify. */ + portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_READ_ONLY ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup unprivileged syscalls flash as Read Only by both privileged - * and unprivileged tasks. All tasks can read it but no-one can modify. */ - portMPU_RNR_REG = portUNPRIVILEGED_SYSCALLS_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __syscalls_flash_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_READ_ONLY ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __syscalls_flash_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Setup RAM containing kernel data for privileged access only. */ + portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; + portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | + ( portMPU_REGION_NON_SHAREABLE ) | + ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + ( portMPU_REGION_EXECUTE_NEVER ); + portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | + ( portMPU_RLAR_ATTR_INDEX0 ) | + ( portMPU_RLAR_REGION_ENABLE ); - /* Setup RAM containing kernel data for privileged access only. */ - portMPU_RNR_REG = portPRIVILEGED_RAM_REGION; - portMPU_RBAR_REG = ( ( ( uint32_t ) __privileged_sram_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | - ( portMPU_REGION_NON_SHAREABLE ) | - ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_EXECUTE_NEVER ); - portMPU_RLAR_REG = ( ( ( uint32_t ) __privileged_sram_end__ ) & portMPU_RLAR_ADDRESS_MASK ) | - ( portMPU_RLAR_ATTR_INDEX0 ) | - ( portMPU_RLAR_REGION_ENABLE ); + /* Enable mem fault. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - /* Enable mem fault. */ - portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_MEM_FAULT_ENABLE_BIT; - - /* Enable MPU with privileged background access i.e. unmapped - * regions have privileged access. */ - portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); - } + /* Enable MPU with privileged background access i.e. unmapped + * regions have privileged access. */ + portMPU_CTRL_REG |= ( portMPU_PRIV_BACKGROUND_ENABLE_BIT | portMPU_ENABLE_BIT ); } #endif /* configENABLE_MPU */ @@ -1027,28 +1049,29 @@ } /*-----------------------------------------------------------*/ -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 ) +#if ( configNUMBER_OF_CORES == 1 ) + void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */ { - 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 */ @@ -1056,6 +1079,10 @@ uint32_t ulPreviousMask; 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(); { /* Increment the RTOS tick. */ @@ -1070,6 +1097,10 @@ traceISR_EXIT(); } } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ @@ -1078,7 +1109,6 @@ { #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) #if defined( __ARMCC_VERSION ) - /* Declaration when these variable are defined in code instead of being * exported from linker scripts. */ extern uint32_t * __syscalls_flash_start__; @@ -1090,6 +1120,19 @@ #endif /* defined( __ARMCC_VERSION ) */ #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + #if ( configENABLE_MPU == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __privileged_functions_start__; + extern uint32_t * __privileged_functions_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __privileged_functions_start__[]; + extern uint32_t __privileged_functions_end__[]; + #endif /* defined( __ARMCC_VERSION ) */ + #endif /* configENABLE_MPU == 1 */ + uint32_t ulPC; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1108,38 +1151,42 @@ switch( ucSVCNumber ) { - #if ( configENABLE_TRUSTZONE == 1 ) - case portSVC_ALLOCATE_SECURE_CONTEXT: + #if ( configENABLE_TRUSTZONE == 1 ) + case portSVC_ALLOCATE_SECURE_CONTEXT: - /* R0 contains the stack size passed as parameter to the - * vPortAllocateSecureContext function. */ - ulR0 = pulCallerStackAddress[ 0 ]; + /* R0 contains the stack size passed as parameter to the + * vPortAllocateSecureContext function. */ + ulR0 = pulCallerStackAddress[ 0 ]; - #if ( configENABLE_MPU == 1 ) - { - /* Read the CONTROL register value. */ - __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); + #if ( configENABLE_MPU == 1 ) + { + /* Read the CONTROL register value. */ + __asm volatile ( "mrs %0, control" : "=r" ( ulControl ) ); - /* The task that raised the SVC is privileged if Bit[0] - * in the CONTROL register is 0. */ - ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); + /* The task that raised the SVC is privileged if Bit[0] + * in the CONTROL register is 0. */ + ulIsTaskPrivileged = ( ( ulControl & portCONTROL_PRIVILEGED_MASK ) == 0 ); - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); - } - #else /* if ( configENABLE_MPU == 1 ) */ - { - /* Allocate and load a context for the secure task. */ - xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); - } - #endif /* configENABLE_MPU */ + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged, pxCurrentTCB ); + } + #else /* if ( configENABLE_MPU == 1 ) */ + { + /* Allocate and load a context for the secure task. */ + xSecureContext = SecureContext_AllocateContext( ulR0, pxCurrentTCB ); + } + #endif /* configENABLE_MPU */ - configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); - SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); - break; + configASSERT( xSecureContext != securecontextINVALID_CONTEXT_ID ); + SecureContext_LoadContext( xSecureContext, pxCurrentTCB ); + break; - case portSVC_FREE_SECURE_CONTEXT: - + case portSVC_FREE_SECURE_CONTEXT: + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) + { + #endif /* configENABLE_MPU */ /* R0 contains TCB being freed and R1 contains the secure * context handle to be freed. */ ulR0 = pulCallerStackAddress[ 0 ]; @@ -1147,51 +1194,62 @@ /* Free the secure context. */ SecureContext_FreeContext( ( SecureContextHandle_t ) ulR1, ( void * ) ulR0 ); - break; - #endif /* configENABLE_TRUSTZONE */ + #if ( configENABLE_MPU == 1 ) + } + #endif /* configENABLE_MPU */ + break; + #endif /* configENABLE_TRUSTZONE */ case portSVC_START_SCHEDULER: - #if ( configENABLE_TRUSTZONE == 1 ) + #if ( configENABLE_MPU == 1 ) + if( ( ulPC >= ( uint32_t ) __privileged_functions_start__ ) && + ( ulPC <= ( uint32_t ) __privileged_functions_end__ ) ) { - /* De-prioritize the non-secure exceptions so that the - * non-secure pendSV runs at the lowest priority. */ - SecureInit_DePrioritizeNSExceptions(); + #endif /* configENABLE_MPU */ + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* De-prioritize the non-secure exceptions so that the + * non-secure pendSV runs at the lowest priority. */ + SecureInit_DePrioritizeNSExceptions(); - /* Initialize the secure context management system. */ - SecureContext_Init(); + /* Initialize the secure context management system. */ + SecureContext_Init(); + } + #endif /* configENABLE_TRUSTZONE */ + + #if ( configENABLE_FPU == 1 ) + { + /* Setup the Floating Point Unit (FPU). */ + prvSetupFPU(); + } + #endif /* configENABLE_FPU */ + + /* Setup the context of the first task so that the first task starts + * executing. */ + vRestoreContextOfFirstTask(); + #if ( configENABLE_MPU == 1 ) } - #endif /* configENABLE_TRUSTZONE */ - - #if ( configENABLE_FPU == 1 ) - { - /* Setup the Floating Point Unit (FPU). */ - prvSetupFPU(); - } - #endif /* configENABLE_FPU */ - - /* Setup the context of the first task so that the first task starts - * executing. */ - vRestoreContextOfFirstTask(); + #endif /* configENABLE_MPU */ break; - #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) - case portSVC_RAISE_PRIVILEGE: + #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) ) + case portSVC_RAISE_PRIVILEGE: - /* Only raise the privilege, if the svc was raised from any of - * the system calls. */ - if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && - ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) - { - vRaisePrivilege(); - } - break; - #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ + /* Only raise the privilege, if the svc was raised from any of + * the system calls. */ + if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) && + ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ) + { + vRaisePrivilege(); + } + break; + #endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 1 ) */ - #if ( configENABLE_MPU == 1 ) - case portSVC_YIELD: - vPortYield(); - break; - #endif /* configENABLE_MPU == 1 */ + #if ( configENABLE_MPU == 1 ) + case portSVC_YIELD: + vPortYield(); + break; + #endif /* configENABLE_MPU == 1 */ default: /* Incorrect SVC call. */ @@ -1210,7 +1268,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1246,12 +1304,16 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1261,20 +1323,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -1310,7 +1372,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Record if the hardware used padding to force the stack pointer * to be double word aligned. */ @@ -1360,7 +1422,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i; #if defined( __ARMCC_VERSION ) @@ -1392,12 +1454,16 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) { if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; __asm volatile ( " vpush {s0} \n" /* Trigger lazy stacking. */ " vpop {s0} \n" /* Nullify the affect of the above instruction. */ @@ -1407,20 +1473,20 @@ else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } } #else /* if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */ { - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } #endif /* configENABLE_FPU || configENABLE_MVE */ /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1518,21 +1584,21 @@ xMPUSettings->ulContext[ ulIndex ] = 0x11111111; /* r11. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pvParameters; /* r0. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ + xMPUSettings->ulContext[ ulIndex ] = 0x01010101; /* r1. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ + xMPUSettings->ulContext[ ulIndex ] = 0x02020202; /* r2. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ + xMPUSettings->ulContext[ ulIndex ] = 0x03030303; /* r3. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ + xMPUSettings->ulContext[ ulIndex ] = 0x12121212; /* r12. */ ulIndex++; xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) portTASK_RETURN_ADDRESS; /* LR. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxCode; /* PC. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ + xMPUSettings->ulContext[ ulIndex ] = portINITIAL_XPSR; /* xPSR. */ ulIndex++; #if ( configENABLE_TRUSTZONE == 1 ) @@ -1543,14 +1609,18 @@ #endif /* configENABLE_TRUSTZONE */ xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) ( pxTopOfStack - 8 ); /* PSP with the hardware saved stack. */ ulIndex++; - xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ + xMPUSettings->ulContext[ ulIndex ] = ( uint32_t ) pxEndOfStack; /* PSPLIM. */ ulIndex++; #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Check PACBTI security feature configuration before pushing the * 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 */ @@ -1615,15 +1685,15 @@ * interrupt. */ #if ( portPRELOAD_REGISTERS == 0 ) { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ - pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ - pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + pxTopOfStack -= 9; /* R11..R4, EXC_RETURN. */ *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack--; *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ @@ -1637,42 +1707,42 @@ } #else /* portPRELOAD_REGISTERS */ { - pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ - *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC. */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ + *pxTopOfStack = ( StackType_t ) 0x12121212UL; /* R12. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ + *pxTopOfStack = ( StackType_t ) 0x03030303UL; /* R3. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ + *pxTopOfStack = ( StackType_t ) 0x02020202UL; /* R2. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ + *pxTopOfStack = ( StackType_t ) 0x01010101UL; /* R1. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ + *pxTopOfStack = ( StackType_t ) 0x11111111UL; /* R11. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ + *pxTopOfStack = ( StackType_t ) 0x10101010UL; /* R10. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ + *pxTopOfStack = ( StackType_t ) 0x09090909UL; /* R09. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ + *pxTopOfStack = ( StackType_t ) 0x08080808UL; /* R08. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ + *pxTopOfStack = ( StackType_t ) 0x07070707UL; /* R07. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ + *pxTopOfStack = ( StackType_t ) 0x06060606UL; /* R06. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ + *pxTopOfStack = ( StackType_t ) 0x05050505UL; /* R05. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ + *pxTopOfStack = ( StackType_t ) 0x04040404UL; /* R04. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ + *pxTopOfStack = portINITIAL_EXC_RETURN; /* EXC_RETURN. */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ + *pxTopOfStack = ( StackType_t ) pxEndOfStack; /* Slot used to hold this task's PSPLIM value. */ #if ( configENABLE_TRUSTZONE == 1 ) { @@ -1739,91 +1809,17 @@ } #endif /* configCHECK_HANDLER_INSTALLATION */ - #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; + vPortConfigureInterruptPriorities(); #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) { /* Set the CONTROL register value based on PACBTI security feature * 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 */ @@ -1834,12 +1830,47 @@ } #endif /* configENABLE_MPU */ - /* Start the timer that generates the tick ISR. Interrupts are disabled - * here already. */ - vPortSetupTimerInterrupt(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Start the timer that generates the tick ISR. Interrupts are disabled + * 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. */ - ulCriticalNesting = 0; + /* Hold the primary core here until all the secondary cores are ready, this would be achieved only when + * all elements of ucSecondaryCoresReadyFlags are set. + */ + while( 1 ) + { + BaseType_t xAllCoresReady = pdTRUE; + for( uint8_t ucCoreID = 0; ucCoreID < ( configNUMBER_OF_CORES - 1 ); ucCoreID++ ) + { + if( ucSecondaryCoresReadyFlags[ ucCoreID ] != pdTRUE ) + { + xAllCoresReady = pdFALSE; + break; + } + } + + if ( xAllCoresReady == pdTRUE ) + { + break; + } + } + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + /* Start the timer that generates the tick ISR. */ + 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 ) ) { @@ -1856,7 +1887,11 @@ * functionality by defining configTASK_RETURN_ADDRESS. Call * vTaskSwitchContext() so link time optimization does not remove the * symbol. */ - vTaskSwitchContext(); + #if ( configNUMBER_OF_CORES > 1 ) + vTaskSwitchContext( portGET_CORE_ID() ); + #else + vTaskSwitchContext(); + #endif prvTaskExitError(); /* Should not get here. */ @@ -1868,7 +1903,11 @@ { /* Not implemented in ports where there is nothing to return to. * 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 ) */ } /*-----------------------------------------------------------*/ @@ -2151,6 +2190,90 @@ #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 ) ) void vPortGrantAccessToKernelObject( TaskHandle_t xInternalTaskHandle, @@ -2247,36 +2370,214 @@ /*-----------------------------------------------------------*/ #if ( ( configENABLE_PAC == 1 ) || ( configENABLE_BTI == 1 ) ) - - static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) - { - uint32_t ulControl = 0x0; - - /* 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 ) + #if ( configNUMBER_OF_CORES == 1 ) + static uint32_t prvConfigurePACBTI( BaseType_t xWriteControlRegister ) + #else /* configNUMBER_OF_CORES > 1 */ + uint32_t vConfigurePACBTI( BaseType_t xWriteControlRegister ) + #endif /* configNUMBER_OF_CORES */ { - ulControl |= ( portCONTROL_UPAC_EN | portCONTROL_PAC_EN ); - } - #endif + uint32_t ulControl = 0x0; - #if ( configENABLE_BTI == 1 ) - { - ulControl |= ( portCONTROL_UBTI_EN | portCONTROL_BTI_EN ); - } - #endif + /* Ensure that PACBTI is implemented. */ + configASSERT( portID_ISAR5_REG != 0x0 ); - if( xWriteControlRegister == pdTRUE ) - { - __asm volatile ( "msr control, %0" : : "r" ( ulControl ) ); - } + /* Enable UsageFault exception. */ + portSCB_SYS_HANDLER_CTRL_STATE_REG |= portSCB_USG_FAULT_ENABLE_BIT; - 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 */ /*-----------------------------------------------------------*/ + +#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 ) */
diff --git a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.h b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.h index 53b4b6e..b4b545f 100644 --- a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.h +++ b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.s b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.s index 8092255..8de575d 100644 --- a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.s +++ b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portasm.s
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -41,7 +40,15 @@ #define configUSE_MPU_WRAPPERS_V1 0 #endif +#ifndef configNUMBER_OF_CORES + #define configNUMBER_OF_CORES 1 +#endif + +#if ( configNUMBER_OF_CORES == 1) EXTERN pxCurrentTCB +#else /* if ( configNUMBER_OF_CORES == 1) */ + EXTERN pxCurrentTCBs +#endif EXTERN vTaskSwitchContext EXTERN vPortSVCHandler_C #if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) ) @@ -169,8 +176,15 @@ #else /* configENABLE_MPU */ vRestoreContextOfFirstTask: +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ #if ( configENABLE_PAC == 1 ) @@ -193,6 +207,13 @@ mov r0, #0 msr basepri, r0 /* Ensure that interrupts are enabled when the first task starts. */ 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 */ /*-----------------------------------------------------------*/ @@ -377,20 +398,37 @@ clrm {r1-r4} /* Clear r1-r4. */ #endif /* configENABLE_PAC */ +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 /* Disable interrupts up to configMAX_SYSCALL_INTERRUPT_PRIORITY. */ dsb isb + #if ( configNUMBER_OF_CORES > 1) + mov r0, r2 /* r0 = ucPortGetCoreID() */ + #endif /* if ( configNUMBER_OF_CORES == 1) */ bl vTaskSwitchContext mov r0, #0 /* r0 = 0. */ msr basepri, r0 /* Enable interrupts. */ +#if ( configNUMBER_OF_CORES == 1) ldr r2, =pxCurrentTCB /* Read the location of pxCurrentTCB i.e. &( 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. */ #if ( configENABLE_PAC == 1 ) @@ -413,6 +451,13 @@ msr psplim, r2 /* Restore the PSPLIM register value for the task. */ msr psp, r0 /* Remember the new top of stack for the task. */ 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 */ /*-----------------------------------------------------------*/
diff --git a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacro.h b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacro.h index 2f1676c..4b2faaf 100644 --- a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacro.h +++ b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacro.h
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -57,6 +58,7 @@ #define portHAS_ARMV8M_MAIN_EXTENSION 1 #define portARMV8M_MINOR_VERSION 1 #define portDONT_DISCARD __root +#define portVALIDATED_FOR_SMP 0 /*-----------------------------------------------------------*/ /* ARMv8-M common port configurations. */
diff --git a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacrocommon.h b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacrocommon.h index 2dfac6a..c34fdee 100644 --- a/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacrocommon.h +++ b/Source/portable/IAR/ARM_CM85_NTZ/non_secure/portmacrocommon.h
@@ -1,8 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Copyright 2024 Arm Limited and/or its affiliates - * <open-source-office@arm.com> + * Copyright 2024, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -59,6 +58,19 @@ #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 */ +#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 ) */ /*-----------------------------------------------------------*/ /** @@ -428,10 +440,26 @@ /** * @brief Critical section management. */ + +#define portSET_INTERRUPT_MASK() ulSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vClearInterruptMask( x ) #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask() #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 +554,7 @@ /* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION * based on whether or not Mainline extension is implemented. */ #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 #else #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 @@ -573,6 +601,44 @@ #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* */ #ifdef __cplusplus }
diff --git a/Source/portable/MemMang/heap_1.c b/Source/portable/MemMang/heap_1.c index 30f3e13..08a3ec1 100644 --- a/Source/portable/MemMang/heap_1.c +++ b/Source/portable/MemMang/heap_1.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/MemMang/heap_2.c b/Source/portable/MemMang/heap_2.c index 0c6f3c2..5832a7d 100644 --- a/Source/portable/MemMang/heap_2.c +++ b/Source/portable/MemMang/heap_2.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/MemMang/heap_3.c b/Source/portable/MemMang/heap_3.c index e64c89c..89ca036 100644 --- a/Source/portable/MemMang/heap_3.c +++ b/Source/portable/MemMang/heap_3.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/MemMang/heap_4.c b/Source/portable/MemMang/heap_4.c index ef2db1c..cb47359 100644 --- a/Source/portable/MemMang/heap_4.c +++ b/Source/portable/MemMang/heap_4.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -572,7 +572,7 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats ) { BlockLink_t * pxBlock; - size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */ + size_t xBlocks = 0, xMaxSize = 0, xMinSize = SIZE_MAX; vTaskSuspendAll(); {
diff --git a/Source/portable/MemMang/heap_5.c b/Source/portable/MemMang/heap_5.c index dcfcca7..b5fdad2 100644 --- a/Source/portable/MemMang/heap_5.c +++ b/Source/portable/MemMang/heap_5.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -284,7 +284,14 @@ { pxPreviousBlock = pxBlock; pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock ); - heapVALIDATE_BLOCK_POINTER( pxBlock ); + + /* pxEnd is the end marker of the free list. It is located at + * pucHeapHighAddress and is not part of the usable heap, so it + * must be excluded from the heap block pointer validation. */ + if( pxBlock != pxEnd ) + { + heapVALIDATE_BLOCK_POINTER( pxBlock ); + } } /* If the end marker was reached then a block of adequate size @@ -672,7 +679,7 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats ) { BlockLink_t * pxBlock; - size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */ + size_t xBlocks = 0, xMaxSize = 0, xMinSize = SIZE_MAX; vTaskSuspendAll(); {
diff --git a/Source/portable/RVDS/ARM_CA9/port.c b/Source/portable/RVDS/ARM_CA9/port.c index 9fe6e4a..4b62e98 100644 --- a/Source/portable/RVDS/ARM_CA9/port.c +++ b/Source/portable/RVDS/ARM_CA9/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CA9/portASM.s b/Source/portable/RVDS/ARM_CA9/portASM.s index 7184d22..2f934fd 100644 --- a/Source/portable/RVDS/ARM_CA9/portASM.s +++ b/Source/portable/RVDS/ARM_CA9/portASM.s
@@ -1,5 +1,5 @@ ;/* -; * FreeRTOS Kernel V11.2.0 +; * FreeRTOS Kernel V11.3.1 ; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. ; * ; * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CA9/portmacro.h b/Source/portable/RVDS/ARM_CA9/portmacro.h index d59527d..37055dc 100644 --- a/Source/portable/RVDS/ARM_CA9/portmacro.h +++ b/Source/portable/RVDS/ARM_CA9/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CA9/portmacro.inc b/Source/portable/RVDS/ARM_CA9/portmacro.inc index 574069d..c921cac 100644 --- a/Source/portable/RVDS/ARM_CA9/portmacro.inc +++ b/Source/portable/RVDS/ARM_CA9/portmacro.inc
@@ -1,5 +1,5 @@ ;/* -; * FreeRTOS Kernel V11.2.0 +; * FreeRTOS Kernel V11.3.1 ; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. ; * ; * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM0/port.c b/Source/portable/RVDS/ARM_CM0/port.c index 378a850..a8a1d8b 100644 --- a/Source/portable/RVDS/ARM_CM0/port.c +++ b/Source/portable/RVDS/ARM_CM0/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM0/portmacro.h b/Source/portable/RVDS/ARM_CM0/portmacro.h index 5fad46d..650fe66 100644 --- a/Source/portable/RVDS/ARM_CM0/portmacro.h +++ b/Source/portable/RVDS/ARM_CM0/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM3/port.c b/Source/portable/RVDS/ARM_CM3/port.c index 9f95488..e38c162 100644 --- a/Source/portable/RVDS/ARM_CM3/port.c +++ b/Source/portable/RVDS/ARM_CM3/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM3/portmacro.h b/Source/portable/RVDS/ARM_CM3/portmacro.h index 71e4983..1ba54e1 100644 --- a/Source/portable/RVDS/ARM_CM3/portmacro.h +++ b/Source/portable/RVDS/ARM_CM3/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM4F/port.c b/Source/portable/RVDS/ARM_CM4F/port.c index 54c53ce..61055e2 100644 --- a/Source/portable/RVDS/ARM_CM4F/port.c +++ b/Source/portable/RVDS/ARM_CM4F/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM4F/portmacro.h b/Source/portable/RVDS/ARM_CM4F/portmacro.h index 1ed12dd..fc0b9c4 100644 --- a/Source/portable/RVDS/ARM_CM4F/portmacro.h +++ b/Source/portable/RVDS/ARM_CM4F/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM4_MPU/mpu_wrappers_v2_asm.c b/Source/portable/RVDS/ARM_CM4_MPU/mpu_wrappers_v2_asm.c index 76a50bb..c46c9e3 100644 --- a/Source/portable/RVDS/ARM_CM4_MPU/mpu_wrappers_v2_asm.c +++ b/Source/portable/RVDS/ARM_CM4_MPU/mpu_wrappers_v2_asm.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM4_MPU/port.c b/Source/portable/RVDS/ARM_CM4_MPU/port.c index a491d4b..824c225 100644 --- a/Source/portable/RVDS/ARM_CM4_MPU/port.c +++ b/Source/portable/RVDS/ARM_CM4_MPU/port.c
@@ -1,6 +1,8 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2025 Arm Limited and/or its affiliates + * <open-source-office@arm.com> * * SPDX-License-Identifier: MIT * @@ -46,9 +48,19 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE +/* Unprivileged critical sections are not supported when using MPU wrappers + * version 2. Default the option to 0 and reject an explicit value of 1. */ #ifndef configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS - #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." - #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0 + #else + #warning "configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not defined. We recommend defining it to 0 in FreeRTOSConfig.h for better security." + #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 + #endif +#else + #if ( ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS == 1 ) ) + #error configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS is not supported with MPU wrappers version 2 ( configUSE_MPU_WRAPPERS_V1 == 0 ). + #endif #endif /* Prototype of all Interrupt Service Routines (ISRs). */ @@ -474,7 +486,7 @@ extern UBaseType_t uxSystemCallImplementations[ NUM_SYSTEM_CALLS ]; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulSystemCallStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i, r1; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i, r1; extern uint32_t __syscalls_flash_start__; extern uint32_t __syscalls_flash_end__; @@ -500,23 +512,27 @@ { pulSystemCallStack = pxMpuSettings->xSystemCallStackInfo.pulSystemCallStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; prvTriggerLazyStacking(); } else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } /* Make space on the system call stack for the stack frame. */ - pulSystemCallStack = pulSystemCallStack - ulStackFrameSize; + pulSystemCallStack = pulSystemCallStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulSystemCallStack[ i ] = pulTaskStack[ i ]; } @@ -537,7 +553,7 @@ /* Remember the location where we should copy the stack frame when we exit from * the system call. */ - pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulStackFrameSize; + pxMpuSettings->xSystemCallStackInfo.pulTaskStack = pulTaskStack + ulHardwareSavedExceptionFrameSize; /* Store the value of the Link Register before the SVC was raised. * It contains the address of the caller of the System Call entry @@ -592,7 +608,7 @@ extern TaskHandle_t pxCurrentTCB; xMPU_SETTINGS * pxMpuSettings; uint32_t * pulTaskStack; - uint32_t ulStackFrameSize, ulSystemCallLocation, i, r1; + uint32_t ulHardwareSavedExceptionFrameSize, ulSystemCallLocation, i, r1; extern uint32_t __privileged_functions_start__; extern uint32_t __privileged_functions_end__; @@ -614,23 +630,27 @@ { pulTaskStack = pxMpuSettings->xSystemCallStackInfo.pulTaskStack; + /* Hardware Saved Stack Frame Size upon Exception entry: + * - No FPU: basic frame (R0-R3, R12, LR, PC, and xPSR) = 8 words. + * - With FPU (lazy stacking): basic frame + S0–S15 + FPSCR + reserved word = 26 words. + */ if( ( ulLR & portEXC_RETURN_STACK_FRAME_TYPE_MASK ) == 0UL ) { /* Extended frame i.e. FPU in use. */ - ulStackFrameSize = 26; + ulHardwareSavedExceptionFrameSize = 26; prvTriggerLazyStacking(); } else { /* Standard frame i.e. FPU not in use. */ - ulStackFrameSize = 8; + ulHardwareSavedExceptionFrameSize = 8; } /* Make space on the task stack for the stack frame. */ - pulTaskStack = pulTaskStack - ulStackFrameSize; + pulTaskStack = pulTaskStack - ulHardwareSavedExceptionFrameSize; /* Copy the stack frame. */ - for( i = 0; i < ulStackFrameSize; i++ ) + for( i = 0; i < ulHardwareSavedExceptionFrameSize; i++ ) { pulTaskStack[ i ] = pulSystemCallStack[ i ]; } @@ -1331,7 +1351,7 @@ } /* Shift the code by one before returning so it can be written directly - * into the the correct bit position of the attribute register. */ + * into the correct bit position of the attribute register. */ return( ulReturnValue << 1UL ); } /*-----------------------------------------------------------*/
diff --git a/Source/portable/RVDS/ARM_CM4_MPU/portmacro.h b/Source/portable/RVDS/ARM_CM4_MPU/portmacro.h index 9a6e37d..e2741ab 100644 --- a/Source/portable/RVDS/ARM_CM4_MPU/portmacro.h +++ b/Source/portable/RVDS/ARM_CM4_MPU/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM7/r0p1/port.c b/Source/portable/RVDS/ARM_CM7/r0p1/port.c index 1d0e460..7294dec 100644 --- a/Source/portable/RVDS/ARM_CM7/r0p1/port.c +++ b/Source/portable/RVDS/ARM_CM7/r0p1/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/RVDS/ARM_CM7/r0p1/portmacro.h b/Source/portable/RVDS/ARM_CM7/r0p1/portmacro.h index ef1389a..9cb7a51 100644 --- a/Source/portable/RVDS/ARM_CM7/r0p1/portmacro.h +++ b/Source/portable/RVDS/ARM_CM7/r0p1/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/Tasking/ARM_CM4F/port.c b/Source/portable/Tasking/ARM_CM4F/port.c index 577bbb8..bf0466b 100644 --- a/Source/portable/Tasking/ARM_CM4F/port.c +++ b/Source/portable/Tasking/ARM_CM4F/port.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/Tasking/ARM_CM4F/port_asm.asm b/Source/portable/Tasking/ARM_CM4F/port_asm.asm index 3022668..15308ae 100644 --- a/Source/portable/Tasking/ARM_CM4F/port_asm.asm +++ b/Source/portable/Tasking/ARM_CM4F/port_asm.asm
@@ -1,5 +1,5 @@ ;/* -; * FreeRTOS Kernel V11.2.0 +; * FreeRTOS Kernel V11.3.1 ; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. ; * ; * SPDX-License-Identifier: MIT
diff --git a/Source/portable/Tasking/ARM_CM4F/portmacro.h b/Source/portable/Tasking/ARM_CM4F/portmacro.h index 0f2e3be..02907d5 100644 --- a/Source/portable/Tasking/ARM_CM4F/portmacro.h +++ b/Source/portable/Tasking/ARM_CM4F/portmacro.h
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT
diff --git a/Source/portable/ThirdParty/GCC/ARM_TFM/README.md b/Source/portable/ThirdParty/GCC/ARM_TFM/README.md new file mode 100644 index 0000000..c419a01 --- /dev/null +++ b/Source/portable/ThirdParty/GCC/ARM_TFM/README.md
@@ -0,0 +1,80 @@ +# Target of this port + +This port adds the support that FreeRTOS applications can call the secure +services in Trusted Firmware M(TF-M) through Platform Security Architecture +(PSA) API based on the ARM Cortex-M23, Cortex-M33, Cortex-M52, Cortex-M55, +Cortex-M85 and Arm China STAR-MC3 platform. + +The Platform Security Architecture (PSA) makes it quicker, easier and cheaper +to design security into a device from the ground up. PSA is made up of four key +stages: analyze, architect, implement, and certify. See [PSA Resource Page](https://www.arm.com/architecture/security-features/platform-security). + +TF-M is an open source project. It provides a reference implementation of PSA +for Arm M-profile architecture. Please get the details from this [link](https://www.trustedfirmware.org/projects/tf-m/). + +# Derivation of the source code + +* `os_wrapper_freertos.c` + The implementation of APIs which are defined in `/interface/include/os_wrapper/mutex.h` + in trusted-firmware-m (tag: TF-Mv2.0.0). The implementation is based on + FreeRTOS mutex type semaphore. + +# Usage notes + +To build a project based on this port: +* Step 1: build the secure image. Please follow the **Build the Secure Side** section for details. +* Step 2: build the nonsecure image. Please follow the **Build the Non-Secure Side** for details. + +## Build the Secure Side + +### Get the TF-M source code + +See the [link](https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/) to get the source code. This port is supported by TF-M version **tag: TF-Mv2.0.0**. + +### Build TF-M + +Please refer to this [link](https://trustedfirmware-m.readthedocs.io/en/latest/getting_started/) to build the secure side. +_**Note:** `TFM_NS_MANAGE_NSID` must be configured as "OFF" when building TF-M_. + +## Build the Non-Secure Side + +Please copy all the files in `freertos_kernel/portable/GCC/ARM_[CM23|CM33|CM52|CM55|CM85|STAR_MC3]_NTZ` into the `freertos_kernel/portable/ThirdParty/GCC/ARM_TFM` folder before using this port. Note that TrustZone is enabled in this port. The TF-M runs in the Secure Side. + +Please call the API `tfm_ns_interface_init()` which is defined in `/interface/src/os_wrapper/tfm_ns_interface_rtos.c` by trusted-firmware-m (tag: TF-Mv2.0.0) at the very beginning of your application. Otherwise, it will always fail when calling a TF-M service in the Nonsecure Side. + +### Configuration in FreeRTOS kernel + +* `configRUN_FREERTOS_SECURE_ONLY` +This macro should be configured as 0. In this port, TF-M runs in the Secure Side while FreeRTOS +Kernel runs in the Non-Secure Side. + +* `configENABLE_FPU` +The setting of this macro is decided by the setting in Secure Side which is platform-specific. +If the Secure Side enables Non-Secure access to FPU, then this macro can be configured as 0 or 1. Otherwise, this macro can only be configured as 0. +Please note that Cortex-M23 does not support FPU. +Please refer to [TF-M documentation](https://trustedfirmware-m.readthedocs.io/en/latest/integration_guide/tfm_fpu_support.html) for FPU usage on the Non-Secure side. + +* `configENABLE_MVE` +The setting of this macro is decided by the setting in Secure Side which is platform-specific. +If the Secure Side enables Non-Secure access to MVE, then this macro can be configured as 0 or 1. Otherwise, this macro can only be configured as 0. +Please note that only Cortex-M52, Cortex-M55, Cortex-M85 and STAR-MC3 support MVE. +Please refer to [TF-M documentation](https://trustedfirmware-m.readthedocs.io/en/latest/integration_guide/tfm_fpu_support.html) for MVE usage on the Non-Secure side. + +* `configENABLE_TRUSTZONE` +This macro should be configured as 0 because TF-M doesn't use the secure context management function of FreeRTOS. New secure context management might be introduced when TF-M supports multiple secure context. + + +### Integrate TF-M Non-Secure interface with FreeRTOS project + +To enable calling TF-M services by the Non-Secure Side, the files below should be included in the FreeRTOS project and built together. +* files in `trusted-firmware-m/build/api_ns/interface/src` + These files contain the implementation of PSA Functional Developer APIs which can be called by Non-Secure Side directly and PSA Firmware Framework APIs in the IPC model. These files should be taken as part of the Non-Secure source code. +* files in `trusted-firmware-m/build/api_ns/interface/include` + These files are the necessary header files to call TF-M services. +* `trusted-firmware-m/build/api_ns/interface/lib/s_veneers.o` + This object file contains all the Non-Secure callable functions exported by + TF-M and it should be linked when generating the Non-Secure image. + + + +*Copyright (c) 2020-2024, Arm Limited. All rights reserved.*
diff --git a/Source/portable/ThirdParty/GCC/ARM_TFM/os_wrapper_freertos.c b/Source/portable/ThirdParty/GCC/ARM_TFM/os_wrapper_freertos.c new file mode 100644 index 0000000..35add2b --- /dev/null +++ b/Source/portable/ThirdParty/GCC/ARM_TFM/os_wrapper_freertos.c
@@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019-2024, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/* + * This file contains the implementation of APIs which are defined in + * \interface/include/os_wrapper/mutex.h by TF-M(tag: TF-Mv2.0.0). + * The implementation is based on FreeRTOS mutex type semaphore. + */ + +#include "os_wrapper/mutex.h" + +#include "FreeRTOS.h" +#include "semphr.h" +#include "mpu_wrappers.h" + +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + +/* + * In the static allocation, the RAM is required to hold the semaphore's + * state. + */ + StaticSemaphore_t xSecureMutexBuffer; +#endif + +void * os_wrapper_mutex_create( void ) +{ + SemaphoreHandle_t xMutexHandle = NULL; + + #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + xMutexHandle = xSemaphoreCreateMutex(); + #elif ( configSUPPORT_STATIC_ALLOCATION == 1 ) + xMutexHandle = xSemaphoreCreateMutexStatic( &xSecureMutexBuffer ); + #endif + return ( void * ) xMutexHandle; +} +/*-----------------------------------------------------------*/ + +uint32_t os_wrapper_mutex_acquire( void * handle, + uint32_t timeout ) +{ + BaseType_t xRet; + + if( !handle ) + { + return OS_WRAPPER_ERROR; + } + + xRet = xSemaphoreTake( ( SemaphoreHandle_t ) handle, + ( timeout == OS_WRAPPER_WAIT_FOREVER ) ? + portMAX_DELAY : ( TickType_t ) timeout ); + + if( xRet != pdPASS ) + { + return OS_WRAPPER_ERROR; + } + else + { + return OS_WRAPPER_SUCCESS; + } +} +/*-----------------------------------------------------------*/ + +uint32_t os_wrapper_mutex_release( void * handle ) +{ + BaseType_t xRet; + + if( !handle ) + { + return OS_WRAPPER_ERROR; + } + + xRet = xSemaphoreGive( ( SemaphoreHandle_t ) handle ); + + if( xRet != pdPASS ) + { + return OS_WRAPPER_ERROR; + } + else + { + return OS_WRAPPER_SUCCESS; + } +} +/*-----------------------------------------------------------*/ + +uint32_t os_wrapper_mutex_delete( void * handle ) +{ + vSemaphoreDelete( ( SemaphoreHandle_t ) handle ); + + return OS_WRAPPER_SUCCESS; +} +/*-----------------------------------------------------------*/
diff --git a/Source/queue.c b/Source/queue.c index 48156f4..00d1a41 100644 --- a/Source/queue.c +++ b/Source/queue.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -563,7 +563,7 @@ return pxNewQueue; } -#endif /* configSUPPORT_STATIC_ALLOCATION */ +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ /*-----------------------------------------------------------*/ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, @@ -833,6 +833,10 @@ if( pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle() ) { ( pxMutex->u.xSemaphore.uxRecursiveCallCount )++; + + /* Check if an overflow occurred. */ + configASSERT( pxMutex->u.xSemaphore.uxRecursiveCallCount ); + xReturn = pdPASS; } else @@ -845,6 +849,9 @@ if( xReturn != pdFAIL ) { ( pxMutex->u.xSemaphore.uxRecursiveCallCount )++; + + /* Check if an overflow occurred. */ + configASSERT( pxMutex->u.xSemaphore.uxRecursiveCallCount ); } else { @@ -1168,9 +1175,8 @@ traceENTER_xQueueGenericSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken, xCopyPosition ); - configASSERT( pxQueue ); - configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); - configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + configASSERT( ( pxQueue != NULL ) && !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( ( pxQueue != NULL ) && !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); /* RTOS ports that support interrupt nesting have the concept of a maximum * system call (or maximum API call) interrupt priority. Interrupts that are @@ -1344,16 +1350,14 @@ * not (i.e. has a task with a higher priority than us been woken by this * post). */ - configASSERT( pxQueue ); - /* xQueueGenericSendFromISR() should be used instead of xQueueGiveFromISR() * if the item size is not 0. */ - configASSERT( pxQueue->uxItemSize == 0 ); + configASSERT( ( pxQueue != NULL ) && ( pxQueue->uxItemSize == 0 ) ); /* Normally a mutex would not be given from an interrupt, especially if * there is a mutex holder, as priority inheritance makes no sense for an - * interrupts, only tasks. */ - configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->u.xSemaphore.xMutexHolder != NULL ) ) ); + * interrupt, only tasks. */ + configASSERT( ( pxQueue != NULL ) && !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->u.xSemaphore.xMutexHolder != NULL ) ) ); /* RTOS ports that support interrupt nesting have the concept of a maximum * system call (or maximum API call) interrupt priority. Interrupts that are @@ -1888,12 +1892,9 @@ traceENTER_xQueuePeek( xQueue, pvBuffer, xTicksToWait ); - /* Check the pointer is not NULL. */ - configASSERT( ( pxQueue ) ); - /* The buffer into which data is received can only be NULL if the data size * is zero (so no data is copied into the buffer. */ - configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( ( pxQueue != NULL ) && !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) ); /* Cannot block if the scheduler is suspended. */ #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) @@ -2145,9 +2146,8 @@ traceENTER_xQueuePeekFromISR( xQueue, pvBuffer ); - configASSERT( pxQueue ); - configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); - configASSERT( pxQueue->uxItemSize != 0 ); /* Can't peek a semaphore. */ + configASSERT( ( pxQueue != NULL ) && !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( ( pxQueue != NULL ) && ( pxQueue->uxItemSize != 0 ) ); /* Can't peek a semaphore. */ /* RTOS ports that support interrupt nesting have the concept of a maximum * system call (or maximum API call) interrupt priority. Interrupts that are @@ -2261,6 +2261,8 @@ traceENTER_vQueueDelete( xQueue ); configASSERT( pxQueue ); + configASSERT( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ); + configASSERT( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ); traceQUEUE_DELETE( pxQueue ); #if ( configQUEUE_REGISTRY_SIZE > 0 ) @@ -3223,7 +3225,16 @@ taskENTER_CRITICAL(); { - if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) + if( ( ( Queue_t * ) xQueueSet )->uxItemSize != ( UBaseType_t ) sizeof( Queue_t * ) ) + { + /* The object passed as the queue set is not a queue set. A queue + * set always has an item size of sizeof( Queue_t * ). Reject any + * other object to prevent a type confusion in which + * prvNotifyQueueSetContainer() would later copy uxItemSize bytes + * from a single pointer on the stack. */ + xReturn = pdFAIL; + } + else if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) { /* Cannot add a queue/semaphore to more than one queue set. */ xReturn = pdFAIL; @@ -3343,6 +3354,8 @@ configASSERT( pxQueueSetContainer ); /* LCOV_EXCL_BR_LINE */ configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); + /* pxQueue->pxQueueSetContainer is verified to be non-null by caller. */ + /* coverity[dereference] */ if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) { const int8_t cTxLock = pxQueueSetContainer->cTxLock;
diff --git a/Source/st_readme.txt b/Source/st_readme.txt index 6915e1b..dc30fbf 100644 --- a/Source/st_readme.txt +++ b/Source/st_readme.txt
@@ -31,6 +31,16 @@ @endverbatim ======= +### 16-October-2026 ### +========================= ++ FreeRTOS: Update to FreeRTOS v11.3.1 + ++ Add folder ARMClang + ++ CMSIS_RTOS_V2 update against the latest CMSIS-FreeRTOS v11.3.1 release + - CMSIS_RTOS_V2/cmsis_os2.c + - CMSIS_RTOS_V2/freertos_os2.h + ### 27-March-2026 ### ========================= + Add SW_Security_Level.md file
diff --git a/Source/stream_buffer.c b/Source/stream_buffer.c index 66a7d07..2736156 100644 --- a/Source/stream_buffer.c +++ b/Source/stream_buffer.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -257,13 +257,22 @@ static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION; /* + * Returns pdTRUE when the amount of buffered data should unblock a task that + * is waiting to receive data. Stream batching buffers require the buffered + * data to exceed the trigger level, whereas stream and message buffers unblock + * when the trigger level is reached. + */ +static BaseType_t prvBytesInBufferMeetTriggerLevel( const StreamBuffer_t * const pxStreamBuffer, + size_t xBytesInBuffer ) PRIVILEGED_FUNCTION; + +/* * Add xCount bytes from pucData into the pxStreamBuffer's data storage area. * This function does not update the buffer's xHead pointer, so multiple writes * may be chained together "atomically". This is useful for Message Buffers where * the length and data bytes are written in two separate chunks, and we don't want * the reader to see the buffer as having grown until after all data is copied over. * This function takes a custom xHead value to indicate where to write to (necessary - * for chaining) and returns the the resulting xHead position. + * for chaining) and returns the resulting xHead position. * To mark the write as complete, manually set the buffer's xHead field with the * returned xHead from this function. */ @@ -305,7 +314,7 @@ * the writer to see the buffer as having more free space until after all data is * copied over, especially if we have to abort the read due to insufficient receiving space. * This function takes a custom xTail value to indicate where to read from (necessary - * for chaining) and returns the the resulting xTail position. + * for chaining) and returns the resulting xTail position. * To mark the read as complete, manually set the buffer's xTail field with the * returned xTail from this function. */ @@ -919,7 +928,7 @@ traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ); /* Was a task waiting for the data? */ - if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) + if( prvBytesInBufferMeetTriggerLevel( pxStreamBuffer, prvBytesInBuffer( pxStreamBuffer ) ) != pdFALSE ) { prvSEND_COMPLETED( pxStreamBuffer ); } @@ -961,6 +970,9 @@ if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) { xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; + + /* Overflow? */ + configASSERT( xRequiredSpace > xDataLengthBytes ); } else { @@ -973,7 +985,7 @@ if( xReturn > ( size_t ) 0 ) { /* Was a task waiting for the data? */ - if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) + if( prvBytesInBufferMeetTriggerLevel( pxStreamBuffer, prvBytesInBuffer( pxStreamBuffer ) ) != pdFALSE ) { /* MISRA Ref 4.7.1 [Return value shall be checked] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */ @@ -1584,6 +1596,35 @@ } /*-----------------------------------------------------------*/ +static BaseType_t prvBytesInBufferMeetTriggerLevel( const StreamBuffer_t * const pxStreamBuffer, + size_t xBytesInBuffer ) +{ + BaseType_t xReturn = pdFALSE; + + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_BATCHING_BUFFER ) != ( uint8_t ) 0 ) + { + if( xBytesInBuffer > pxStreamBuffer->xTriggerLevelBytes ) + { + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xBytesInBuffer >= pxStreamBuffer->xTriggerLevelBytes ) + { + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, uint8_t * const pucBuffer, size_t xBufferSizeBytes, @@ -1653,11 +1694,9 @@ traceENTER_vStreamBufferSetStreamBufferNotificationIndex( xStreamBuffer, uxNotificationIndex ); - configASSERT( pxStreamBuffer ); - /* There should be no task waiting otherwise we'd never resume them. */ - configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL ); - configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL ); + configASSERT( ( pxStreamBuffer != NULL ) && ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) ); + configASSERT( ( pxStreamBuffer != NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) ); /* Check that the task notification index is valid. */ configASSERT( uxNotificationIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES );
diff --git a/Source/tasks.c b/Source/tasks.c index b4c9ba0..c2c01db 100644 --- a/Source/tasks.c +++ b/Source/tasks.c
@@ -1,6 +1,7 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * 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 * @@ -147,7 +148,9 @@ * global, rather than file scope. */ #ifdef portREMOVE_STATIC_QUALIFIER - #define static + #define STATIC +#else + #define STATIC static #endif /* The name allocated to the Idle task. This can be overridden by defining @@ -472,23 +475,23 @@ * xDelayedTaskList1 and xDelayedTaskList2 could be moved to function scope but * doing so breaks some kernel aware debuggers and debuggers that rely on removing * the static qualifier. */ -PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; /**< Prioritised ready tasks. */ -PRIVILEGED_DATA static List_t xDelayedTaskList1; /**< Delayed tasks. */ -PRIVILEGED_DATA static List_t xDelayedTaskList2; /**< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /**< Points to the delayed task list currently being used. */ -PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /**< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t xPendingReadyList; /**< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ +PRIVILEGED_DATA STATIC List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; /**< Prioritised ready tasks. */ +PRIVILEGED_DATA STATIC List_t xDelayedTaskList1; /**< Delayed tasks. */ +PRIVILEGED_DATA STATIC List_t xDelayedTaskList2; /**< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ +PRIVILEGED_DATA STATIC List_t * volatile pxDelayedTaskList; /**< Points to the delayed task list currently being used. */ +PRIVILEGED_DATA STATIC List_t * volatile pxOverflowDelayedTaskList; /**< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ +PRIVILEGED_DATA STATIC List_t xPendingReadyList; /**< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ #if ( INCLUDE_vTaskDelete == 1 ) - PRIVILEGED_DATA static List_t xTasksWaitingTermination; /**< Tasks that have been deleted - but their memory not yet freed. */ - PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; + PRIVILEGED_DATA STATIC List_t xTasksWaitingTermination; /**< Tasks that have been deleted - but their memory not yet freed. */ + PRIVILEGED_DATA STATIC volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; #endif #if ( INCLUDE_vTaskSuspend == 1 ) - PRIVILEGED_DATA static List_t xSuspendedTaskList; /**< Tasks that are currently suspended. */ + PRIVILEGED_DATA STATIC List_t xSuspendedTaskList; /**< Tasks that are currently suspended. */ #endif @@ -499,21 +502,21 @@ #endif /* Other file private variables. --------------------------------*/ -PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; -PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; -PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; -PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U; -PRIVILEGED_DATA static volatile BaseType_t xYieldPendings[ configNUMBER_OF_CORES ] = { pdFALSE }; -PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; -PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ -PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandles[ configNUMBER_OF_CORES ]; /**< Holds the handles of the idle tasks. The idle tasks are created automatically when the scheduler is started. */ +PRIVILEGED_DATA STATIC volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA STATIC volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; +PRIVILEGED_DATA STATIC volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; +PRIVILEGED_DATA STATIC volatile BaseType_t xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA STATIC volatile TickType_t xPendedTicks = ( TickType_t ) 0U; +PRIVILEGED_DATA STATIC volatile BaseType_t xYieldPendings[ configNUMBER_OF_CORES ] = { pdFALSE }; +PRIVILEGED_DATA STATIC volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; +PRIVILEGED_DATA STATIC UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; +PRIVILEGED_DATA STATIC volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA STATIC TaskHandle_t xIdleTaskHandles[ configNUMBER_OF_CORES ]; /**< Holds the handles of the idle tasks. The idle tasks are created automatically when the scheduler is started. */ /* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists. * For tracking the state of remote threads, OpenOCD uses uxTopUsedPriority * to determine the number of priority lists to read back from the remote target. */ -static const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U; +STATIC const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U; /* Context switches are held pending while the scheduler is suspended. Also, * interrupts must not manipulate the xStateListItem of a TCB, or any of the @@ -527,14 +530,14 @@ * Updates to uxSchedulerSuspended must be protected by both the task lock and the ISR lock * and must not be done from an ISR. Reads must be protected by either lock and may be done * from either an ISR or a task. */ -PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) 0U; +PRIVILEGED_DATA STATIC volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) 0U; #if ( configGENERATE_RUN_TIME_STATS == 1 ) /* Do not move these variables to function scope as doing so prevents the * code working with debuggers that need to remove the static qualifier. */ -PRIVILEGED_DATA static configRUN_TIME_COUNTER_TYPE ulTaskSwitchedInTime[ configNUMBER_OF_CORES ] = { 0U }; /**< Holds the value of a timer/counter the last time a task was switched in. */ -PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ configNUMBER_OF_CORES ] = { 0U }; /**< Holds the total amount of execution time as defined by the run time counter clock. */ +PRIVILEGED_DATA STATIC configRUN_TIME_COUNTER_TYPE ulTaskSwitchedInTime[ configNUMBER_OF_CORES ] = { 0U }; /**< Holds the value of a timer/counter the last time a task was switched in. */ +PRIVILEGED_DATA STATIC volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ configNUMBER_OF_CORES ] = { 0U }; /**< Holds the total amount of execution time as defined by the run time counter clock. */ #endif @@ -545,7 +548,7 @@ /* * Creates the idle tasks during scheduler start. */ -static BaseType_t prvCreateIdleTasks( void ); +STATIC BaseType_t prvCreateIdleTasks( void ); #if ( configNUMBER_OF_CORES > 1 ) @@ -553,7 +556,7 @@ * Checks to see if another task moved the current task out of the ready * list while it was waiting to enter a critical section and yields, if so. */ - static void prvCheckForRunStateChange( void ); + STATIC void prvCheckForRunStateChange( void ); #endif /* #if ( configNUMBER_OF_CORES > 1 ) */ #if ( configNUMBER_OF_CORES > 1 ) @@ -562,7 +565,7 @@ * Yields a core, or cores if multiple priorities are not allowed to run * simultaneously, to allow the task pxTCB to run. */ - static void prvYieldForTask( const TCB_t * pxTCB ); + STATIC void prvYieldForTask( const TCB_t * pxTCB ); #endif /* #if ( configNUMBER_OF_CORES > 1 ) */ #if ( configNUMBER_OF_CORES > 1 ) @@ -570,7 +573,7 @@ /* * Selects the highest priority available task for the given core. */ - static void prvSelectHighestPriorityTask( BaseType_t xCoreID ); + STATIC void prvSelectHighestPriorityTask( BaseType_t xCoreID ); #endif /* #if ( configNUMBER_OF_CORES > 1 ) */ /** @@ -580,7 +583,7 @@ */ #if ( INCLUDE_vTaskSuspend == 1 ) - static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + STATIC BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; #endif /* INCLUDE_vTaskSuspend */ @@ -588,7 +591,7 @@ * Utility to ready all the lists used by the scheduler. This is called * automatically upon the creation of the first task. */ -static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; +STATIC void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; /* * The idle task, which as all tasks is implemented as a never ending loop. @@ -606,9 +609,11 @@ * void prvPassiveIdleTask( void *pvParameters ); * */ -static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION; +STATIC portTASK_FUNCTION_PROTO( prvIdleTask, + pvParameters ) PRIVILEGED_FUNCTION; #if ( configNUMBER_OF_CORES > 1 ) - static portTASK_FUNCTION_PROTO( prvPassiveIdleTask, pvParameters ) PRIVILEGED_FUNCTION; + STATIC portTASK_FUNCTION_PROTO( prvPassiveIdleTask, + pvParameters ) PRIVILEGED_FUNCTION; #endif /* @@ -620,7 +625,7 @@ */ #if ( INCLUDE_vTaskDelete == 1 ) - static void prvDeleteTCB( TCB_t * pxTCB ) PRIVILEGED_FUNCTION; + STATIC void prvDeleteTCB( TCB_t * pxTCB ) PRIVILEGED_FUNCTION; #endif @@ -629,38 +634,22 @@ * in the list of tasks waiting to be deleted. If so the task is cleaned up * and its TCB deleted. */ -static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; +STATIC void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; /* * The currently executing task is entering the Blocked state. Add the task to * either the current or the overflow delayed task list. */ -static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, +STATIC void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION; /* - * Fills an TaskStatus_t structure with information on each task that is - * referenced from the pxList list (which may be a ready list, a delayed list, - * a suspended list, etc.). - * - * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM - * NORMAL APPLICATION CODE. - */ -#if ( configUSE_TRACE_FACILITY == 1 ) - - static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t * pxTaskStatusArray, - List_t * pxList, - eTaskState eState ) PRIVILEGED_FUNCTION; - -#endif - -/* * Searches pxList for a task with name pcNameToQuery - returning a handle to * the task if it is found, or NULL if the task is not found. */ #if ( INCLUDE_xTaskGetHandle == 1 ) - static TCB_t * prvSearchForNameWithinSingleList( List_t * pxList, + STATIC TCB_t * prvSearchForNameWithinSingleList( List_t * pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION; #endif @@ -672,7 +661,7 @@ */ #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) - static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION; + STATIC configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION; #endif @@ -688,7 +677,7 @@ */ #if ( configUSE_TICKLESS_IDLE != 0 ) - static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; + STATIC TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; #endif @@ -696,7 +685,7 @@ * Set xNextTaskUnblockTime to the time at which the next Blocked state task * will exit the Blocked state. */ -static void prvResetNextTaskUnblockTime( void ) PRIVILEGED_FUNCTION; +STATIC void prvResetNextTaskUnblockTime( void ) PRIVILEGED_FUNCTION; #if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) @@ -713,7 +702,7 @@ * Called after a Task_t structure has been allocated either statically or * dynamically to fill in the structure's members. */ -static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, +STATIC void prvInitialiseNewTask( TaskFunction_t pxTaskCode, const char * const pcName, const configSTACK_DEPTH_TYPE uxStackDepth, void * const pvParameters, @@ -726,14 +715,14 @@ * Called after a new task has been created and initialised to place the task * under the control of the scheduler. */ -static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; +STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; /* * Create a task with static buffer for both TCB and stack. Returns a handle to * the task if it is created successfully. Otherwise, returns NULL. */ #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - static TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode, + STATIC TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode, const char * const pcName, const configSTACK_DEPTH_TYPE uxStackDepth, void * const pvParameters, @@ -748,7 +737,7 @@ * a handle to the task if it is created successfully. Otherwise, returns NULL. */ #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) - static TCB_t * prvCreateRestrictedStaticTask( const TaskParameters_t * const pxTaskDefinition, + STATIC TCB_t * prvCreateRestrictedStaticTask( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */ @@ -758,7 +747,7 @@ * returns NULL. */ #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) - static TCB_t * prvCreateRestrictedTask( const TaskParameters_t * const pxTaskDefinition, + STATIC TCB_t * prvCreateRestrictedTask( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ @@ -767,7 +756,7 @@ * the task if it is created successfully. Otherwise, returns NULL. */ #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - static TCB_t * prvCreateTask( TaskFunction_t pxTaskCode, + STATIC TCB_t * prvCreateTask( TaskFunction_t pxTaskCode, const char * const pcName, const configSTACK_DEPTH_TYPE uxStackDepth, void * const pvParameters, @@ -782,7 +771,7 @@ */ #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT - static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION; + STATIC void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION; #endif @@ -812,14 +801,14 @@ * and less than the supplied buffer length, the string has been * completely written. */ - static size_t prvSnprintfReturnValueToCharsWritten( int iSnprintfReturnValue, + STATIC size_t prvSnprintfReturnValueToCharsWritten( int iSnprintfReturnValue, size_t n ); #endif /* #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ /*-----------------------------------------------------------*/ #if ( configNUMBER_OF_CORES > 1 ) - static void prvCheckForRunStateChange( void ) + STATIC void prvCheckForRunStateChange( void ) { UBaseType_t uxPrevCriticalNesting; const TCB_t * pxThisTCB; @@ -887,13 +876,13 @@ /*-----------------------------------------------------------*/ #if ( configNUMBER_OF_CORES > 1 ) - static void prvYieldForTask( const TCB_t * pxTCB ) + STATIC void prvYieldForTask( const TCB_t * pxTCB ) { BaseType_t xLowestPriorityToPreempt; BaseType_t xCurrentCoreTaskPriority; BaseType_t xLowestPriorityCore = ( BaseType_t ) -1; BaseType_t xCoreID; - const BaseType_t xCurrentCoreID = portGET_CORE_ID(); + const BaseType_t xCurrentCoreID = ( BaseType_t ) portGET_CORE_ID(); #if ( configRUN_MULTIPLE_PRIORITIES == 0 ) BaseType_t xYieldCount = 0; @@ -1002,7 +991,7 @@ /*-----------------------------------------------------------*/ #if ( configNUMBER_OF_CORES > 1 ) - static void prvSelectHighestPriorityTask( BaseType_t xCoreID ) + STATIC void prvSelectHighestPriorityTask( BaseType_t xCoreID ) { UBaseType_t uxCurrentPriority = uxTopReadyPriority; BaseType_t xTaskScheduled = pdFALSE; @@ -1273,7 +1262,7 @@ #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - static TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode, + STATIC TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode, const char * const pcName, const configSTACK_DEPTH_TYPE uxStackDepth, void * const pvParameters, @@ -1404,7 +1393,7 @@ /*-----------------------------------------------------------*/ #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) - static TCB_t * prvCreateRestrictedStaticTask( const TaskParameters_t * const pxTaskDefinition, + STATIC TCB_t * prvCreateRestrictedStaticTask( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * const pxCreatedTask ) { TCB_t * pxNewTCB; @@ -1520,7 +1509,7 @@ /*-----------------------------------------------------------*/ #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) - static TCB_t * prvCreateRestrictedTask( const TaskParameters_t * const pxTaskDefinition, + STATIC TCB_t * prvCreateRestrictedTask( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * const pxCreatedTask ) { TCB_t * pxNewTCB; @@ -1639,7 +1628,7 @@ /*-----------------------------------------------------------*/ #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - static TCB_t * prvCreateTask( TaskFunction_t pxTaskCode, + STATIC TCB_t * prvCreateTask( TaskFunction_t pxTaskCode, const char * const pcName, const configSTACK_DEPTH_TYPE uxStackDepth, void * const pvParameters, @@ -1689,7 +1678,7 @@ /* MISRA Ref 11.5.1 [Malloc memory assignment] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ /* coverity[misra_c_2012_rule_11_5_violation] */ - pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) ); + pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) ); if( pxStack != NULL ) { @@ -1812,7 +1801,7 @@ #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ /*-----------------------------------------------------------*/ -static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, +STATIC void prvInitialiseNewTask( TaskFunction_t pxTaskCode, const char * const pcName, const configSTACK_DEPTH_TYPE uxStackDepth, void * const pvParameters, @@ -2007,6 +1996,16 @@ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); } #endif /* portHAS_STACK_OVERFLOW_CHECKING */ + + #if ( portSTACK_GROWTH < 0 ) + { + configASSERT( ( ( portPOINTER_SIZE_TYPE ) ( pxTopOfStack - pxNewTCB->pxTopOfStack ) ) < ( ( portPOINTER_SIZE_TYPE ) uxStackDepth ) ); + } + #else /* portSTACK_GROWTH */ + { + configASSERT( ( ( portPOINTER_SIZE_TYPE ) ( pxNewTCB->pxTopOfStack - pxTopOfStack ) ) < ( ( portPOINTER_SIZE_TYPE ) uxStackDepth ) ); + } + #endif /* portSTACK_GROWTH */ } #endif /* portUSING_MPU_WRAPPERS */ @@ -2038,7 +2037,7 @@ #if ( configNUMBER_OF_CORES == 1 ) - static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) + STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { /* Ensure interrupts don't access the task lists while the lists are being * updated. */ @@ -2116,7 +2115,7 @@ #else /* #if ( configNUMBER_OF_CORES == 1 ) */ - static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) + STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { /* Ensure interrupts don't access the task lists while the lists are being * updated. */ @@ -2177,7 +2176,7 @@ #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) - static size_t prvSnprintfReturnValueToCharsWritten( int iSnprintfReturnValue, + STATIC size_t prvSnprintfReturnValueToCharsWritten( int iSnprintfReturnValue, size_t n ) { size_t uxCharsWritten; @@ -2363,6 +2362,55 @@ #if ( INCLUDE_xTaskDelayUntil == 1 ) + TickType_t xTaskPeriodicDelay( TickType_t * const pxPreviousWakeTime, + const TickType_t xTimeIncrement ) + { + TickType_t xIncrements, xTicksIncrements, xTicksToWait; + + traceENTER_xTaskPeriodicDelay( pxPreviousWakeTime, xTimeIncrement ); + + configASSERT( pxPreviousWakeTime ); + configASSERT( ( xTimeIncrement > 0U ) ); + + vTaskSuspendAll(); + { + /* As long as everything is the same type, this plays well with overflows */ + const TickType_t xTicksElapsed = xTickCount - *pxPreviousWakeTime; + + configASSERT( uxSchedulerSuspended == 1U ); + + /* Number of increments to catch up: it could be 0 if + * not enough ticks have elapsed, 1 in the common case or + * more than 1 if the task has not been resumed in time */ + xIncrements = xTicksElapsed / xTimeIncrement; + xTicksIncrements = xIncrements * xTimeIncrement; + + /* Update to the last wake time */ + *pxPreviousWakeTime += xTicksIncrements; + + /* Ticks to the next wake time */ + xTicksToWait = xTimeIncrement - ( xTicksElapsed - xTicksIncrements ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdFALSE ); + } + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + * have put ourselves to sleep. */ + if( xTaskResumeAll() == pdFALSE ) + { + taskYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceRETURN_xTaskPeriodicDelay( xIncrements ); + + return xIncrements; + } + + BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) { @@ -3309,7 +3357,7 @@ #if ( INCLUDE_vTaskSuspend == 1 ) - static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) + STATIC BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) { BaseType_t xReturn = pdFALSE; const TCB_t * const pxTCB = xTask; @@ -3537,7 +3585,7 @@ #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ /*-----------------------------------------------------------*/ -static BaseType_t prvCreateIdleTasks( void ) +STATIC BaseType_t prvCreateIdleTasks( void ) { BaseType_t xReturn = pdPASS; BaseType_t xCoreID; @@ -3676,8 +3724,13 @@ /* Assign idle task to each core before SMP scheduler is running. */ xIdleTaskHandles[ xCoreID ]->xTaskRunState = xCoreID; pxCurrentTCBs[ xCoreID ] = xIdleTaskHandles[ xCoreID ]; + #if ( ( configIDLE_AFFINITY == 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) + { + xIdleTaskHandles[ xCoreID ]->uxCoreAffinityMask = ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ); + } + #endif /* #if ( ( configIDLE_AFFINITY == 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ } - #endif + #endif /* if ( configNUMBER_OF_CORES == 1 ) */ } } @@ -3946,7 +3999,7 @@ #if ( configUSE_TICKLESS_IDLE != 0 ) - static TickType_t prvGetExpectedIdleTime( void ) + STATIC TickType_t prvGetExpectedIdleTime( void ) { TickType_t xReturn; BaseType_t xHigherPriorityReadyTasks = pdFALSE; @@ -4241,7 +4294,7 @@ /*-----------------------------------------------------------*/ #if ( INCLUDE_xTaskGetHandle == 1 ) - static TCB_t * prvSearchForNameWithinSingleList( List_t * pxList, + STATIC TCB_t * prvSearchForNameWithinSingleList( List_t * pxList, const char pcNameToQuery[] ) { TCB_t * pxReturn = NULL; @@ -4437,11 +4490,107 @@ #if ( configUSE_TRACE_FACILITY == 1 ) + STATIC UBaseType_t prvForEachTaskInList( List_t * pxList, + eTaskState eState, + TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext ); + +/* for uxTaskGetSystemState callback context: current write position into TaskStatusArray */ + typedef struct xTASK_STATUS_ARRAY_WRITER_CONTEXT + { + TaskStatus_t * pxTaskStatusArray; + UBaseType_t uxIndex; + } TaskStatusArrayWriterContext_t; + +/* callback for uxTaskGetSystemState: write one task's status into TaskStatusArray */ + STATIC void prvTaskStatusArrayWriter( TaskHandle_t xTask, + eTaskState eState, + void * pvCallbackContext ) + { + TaskStatusArrayWriterContext_t * pxContext = ( TaskStatusArrayWriterContext_t * ) pvCallbackContext; + + vTaskGetInfo( xTask, &( pxContext->pxTaskStatusArray[ pxContext->uxIndex++ ] ), pdTRUE, eState ); + } + + STATIC void prvGetTotalRunTime( configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) + { + if( pulTotalRunTime != NULL ) + { + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) ); + #else + *pulTotalRunTime = ( configRUN_TIME_COUNTER_TYPE ) portGET_RUN_TIME_COUNTER_VALUE(); + #endif + #else + *pulTotalRunTime = 0; + #endif /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */ + } + } + +/* For each task, call the provided callback function (passing the provided context). */ +/* Caller must suspend the scheduler around use of this function. */ + STATIC UBaseType_t prvCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext ) + { + UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; + + /* Visit each task in the Ready state. */ + do + { + uxQueue--; + uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( &( pxReadyTasksLists[ uxQueue ] ), eReady, pxCallbackFunction, pvCallbackContext ) ); + } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); + + /* Visit each task in the Blocked state. */ + uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( ( List_t * ) pxDelayedTaskList, eBlocked, pxCallbackFunction, pvCallbackContext ) ); + uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( ( List_t * ) pxOverflowDelayedTaskList, eBlocked, pxCallbackFunction, pvCallbackContext ) ); + + #if ( INCLUDE_vTaskDelete == 1 ) + { + /* Visit each task that has been deleted but not yet cleaned up. */ + uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( &xTasksWaitingTermination, eDeleted, pxCallbackFunction, pvCallbackContext ) ); + } + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* Visit each task in the Suspended state. */ + uxTask = ( UBaseType_t ) ( uxTask + prvForEachTaskInList( &xSuspendedTaskList, eSuspended, pxCallbackFunction, pvCallbackContext ) ); + } + #endif + + return uxTask; + } + + UBaseType_t uxTaskCallForEachTask( TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext, + configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) + { + UBaseType_t uxTask; + + configASSERT( pxCallbackFunction != NULL ); + + if( pxCallbackFunction == NULL ) + { + return 0; + } + + vTaskSuspendAll(); + { + uxTask = prvCallForEachTask( pxCallbackFunction, pvCallbackContext ); + prvGetTotalRunTime( pulTotalRunTime ); + } + ( void ) xTaskResumeAll(); + + return uxTask; + } + UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ) { - UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; + UBaseType_t uxTask = 0; traceENTER_uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, pulTotalRunTime ); @@ -4450,54 +4599,11 @@ /* Is there a space in the array for each task in the system? */ if( uxArraySize >= uxCurrentNumberOfTasks ) { - /* Fill in an TaskStatus_t structure with information on each - * task in the Ready state. */ - do - { - uxQueue--; - uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ) ); - } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); - - /* Fill in an TaskStatus_t structure with information on each - * task in the Blocked state. */ - uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ) ); - uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ) ); - - #if ( INCLUDE_vTaskDelete == 1 ) - { - /* Fill in an TaskStatus_t structure with information on - * each task that has been deleted but not yet cleaned up. */ - uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ) ); - } - #endif - - #if ( INCLUDE_vTaskSuspend == 1 ) - { - /* Fill in an TaskStatus_t structure with information on - * each task in the Suspended state. */ - uxTask = ( UBaseType_t ) ( uxTask + prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ) ); - } - #endif - - #if ( configGENERATE_RUN_TIME_STATS == 1 ) - { - if( pulTotalRunTime != NULL ) - { - #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE - portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) ); - #else - *pulTotalRunTime = ( configRUN_TIME_COUNTER_TYPE ) portGET_RUN_TIME_COUNTER_VALUE(); - #endif - } - } - #else /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */ - { - if( pulTotalRunTime != NULL ) - { - *pulTotalRunTime = 0; - } - } - #endif /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */ + TaskStatusArrayWriterContext_t xContext; + xContext.pxTaskStatusArray = pxTaskStatusArray; + xContext.uxIndex = 0; + uxTask = prvCallForEachTask( prvTaskStatusArrayWriter, &xContext ); + prvGetTotalRunTime( pulTotalRunTime ); } else { @@ -5015,11 +5121,11 @@ traceENTER_xTaskGetApplicationTaskTag( xTask ); - /* If xTask is NULL then set the calling task's hook. */ + /* If xTask is NULL then get the calling task's hook. */ pxTCB = prvGetTCBFromHandle( xTask ); configASSERT( pxTCB != NULL ); - /* Save the hook function in the TCB. A critical section is required as + /* Access the hook function in the TCB. A critical section is required as * the value can be accessed from an interrupt. */ taskENTER_CRITICAL(); { @@ -5045,11 +5151,11 @@ traceENTER_xTaskGetApplicationTaskTagFromISR( xTask ); - /* If xTask is NULL then set the calling task's hook. */ + /* If xTask is NULL then get the calling task's hook. */ pxTCB = prvGetTCBFromHandle( xTask ); configASSERT( pxTCB != NULL ); - /* Save the hook function in the TCB. A critical section is required as + /* Access the hook function in the TCB. A critical section is required as * the value can be accessed from an interrupt. */ /* MISRA Ref 4.7.1 [Return value shall be checked] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */ @@ -5728,7 +5834,8 @@ */ #if ( configNUMBER_OF_CORES > 1 ) - static portTASK_FUNCTION( prvPassiveIdleTask, pvParameters ) + STATIC portTASK_FUNCTION( prvPassiveIdleTask, + pvParameters ) { ( void ) pvParameters; @@ -5798,7 +5905,8 @@ * */ -static portTASK_FUNCTION( prvIdleTask, pvParameters ) +STATIC portTASK_FUNCTION( prvIdleTask, + pvParameters ) { /* Stop warnings. */ ( void ) pvParameters; @@ -6064,7 +6172,7 @@ #endif /* portUSING_MPU_WRAPPERS */ /*-----------------------------------------------------------*/ -static void prvInitialiseTaskLists( void ) +STATIC void prvInitialiseTaskLists( void ) { UBaseType_t uxPriority; @@ -6096,7 +6204,7 @@ } /*-----------------------------------------------------------*/ -static void prvCheckTasksWaitingTermination( void ) +STATIC void prvCheckTasksWaitingTermination( void ) { /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/ @@ -6322,9 +6430,10 @@ #if ( configUSE_TRACE_FACILITY == 1 ) - static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t * pxTaskStatusArray, - List_t * pxList, - eTaskState eState ) + STATIC UBaseType_t prvForEachTaskInList( List_t * pxList, + eTaskState eState, + TaskStatusCallbackFunction_t pxCallbackFunction, + void * pvCallbackContext ) { UBaseType_t uxTask = 0; const ListItem_t * pxEndMarker = listGET_END_MARKER( pxList ); @@ -6333,10 +6442,7 @@ if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) { - /* Populate an TaskStatus_t structure within the - * pxTaskStatusArray array for each task that is referenced from - * pxList. See the definition of TaskStatus_t in task.h for the - * meaning of each TaskStatus_t structure member. */ + /* Hand the callback each task handle referenced from pxList. */ for( pxIterator = listGET_HEAD_ENTRY( pxList ); pxIterator != pxEndMarker; pxIterator = listGET_NEXT( pxIterator ) ) { /* MISRA Ref 11.5.3 [Void pointer assignment] */ @@ -6344,7 +6450,7 @@ /* coverity[misra_c_2012_rule_11_5_violation] */ pxTCB = listGET_LIST_ITEM_OWNER( pxIterator ); - vTaskGetInfo( ( TaskHandle_t ) pxTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState ); + pxCallbackFunction( ( TaskHandle_t ) pxTCB, eState, pvCallbackContext ); uxTask++; } } @@ -6361,7 +6467,7 @@ #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) - static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) + STATIC configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) { configSTACK_DEPTH_TYPE uxCount = 0U; @@ -6459,7 +6565,7 @@ #if ( INCLUDE_vTaskDelete == 1 ) - static void prvDeleteTCB( TCB_t * pxTCB ) + STATIC void prvDeleteTCB( TCB_t * pxTCB ) { /* This call is required specifically for the TriCore port. It must be * above the vPortFree() calls. The call is also used by ports/demos that @@ -6512,7 +6618,7 @@ #endif /* INCLUDE_vTaskDelete */ /*-----------------------------------------------------------*/ -static void prvResetNextTaskUnblockTime( void ) +STATIC void prvResetNextTaskUnblockTime( void ) { if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { @@ -6906,7 +7012,7 @@ /* It is known that the task is in its ready list so * there is no need to check again and the port level * reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); } else { @@ -7260,7 +7366,7 @@ #if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) - static char * prvWriteNameToBuffer( char * pcBuffer, + STATIC char * prvWriteNameToBuffer( char * pcBuffer, const char * pcTaskName ) { size_t x; @@ -7340,7 +7446,7 @@ /* MISRA Ref 11.5.1 [Malloc memory assignment] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ /* coverity[misra_c_2012_rule_11_5_violation] */ - pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) ); if( pxTaskStatusArray != NULL ) { @@ -7509,7 +7615,7 @@ /* MISRA Ref 11.5.1 [Malloc memory assignment] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ /* coverity[misra_c_2012_rule_11_5_violation] */ - pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) ); if( pxTaskStatusArray != NULL ) { @@ -7873,7 +7979,7 @@ *pulNotificationValue = pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ]; } - /* If ucNotifyValue is set then either the task never entered the + /* If ucNotifyState is set then either the task never entered the * blocked state (because a notification was already pending) or the * task unblocked because of a notification. Otherwise the task * unblocked because of a timeout. */ @@ -8576,7 +8682,7 @@ #endif /* if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) */ /*-----------------------------------------------------------*/ -static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, +STATIC void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) { TickType_t xTimeToWake; @@ -8728,7 +8834,7 @@ #include "freertos_tasks_c_additions.h" #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT - static void freertos_tasks_c_additions_init( void ) + STATIC void freertos_tasks_c_additions_init( void ) { FREERTOS_TASKS_C_ADDITIONS_INIT(); } @@ -8743,7 +8849,7 @@ * This is the kernel provided implementation of vApplicationGetIdleTaskMemory() * to provide the memory that is used by the Idle task. It is used when * configKERNEL_PROVIDED_STATIC_MEMORY is set to 1. The application can provide - * it's own implementation of vApplicationGetIdleTaskMemory by setting + * its own implementation of vApplicationGetIdleTaskMemory by setting * configKERNEL_PROVIDED_STATIC_MEMORY to 0 or leaving it undefined. */ void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, @@ -8784,7 +8890,7 @@ * This is the kernel provided implementation of vApplicationGetTimerTaskMemory() * to provide the memory that is used by the Timer service task. It is used when * configKERNEL_PROVIDED_STATIC_MEMORY is set to 1. The application can provide - * it's own implementation of vApplicationGetTimerTaskMemory by setting + * its own implementation of vApplicationGetTimerTaskMemory by setting * configKERNEL_PROVIDED_STATIC_MEMORY to 0 or leaving it undefined. */ void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
diff --git a/Source/timers.c b/Source/timers.c index 454be0a..b7e22b1 100644 --- a/Source/timers.c +++ b/Source/timers.c
@@ -1,5 +1,5 @@ /* - * FreeRTOS Kernel V11.2.0 + * FreeRTOS Kernel V11.3.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT @@ -467,9 +467,11 @@ xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; xMessage.u.xTimerParameters.pxTimer = xTimer; - configASSERT( xCommandID < tmrFIRST_FROM_ISR_COMMAND ); + /* Enforce a lower bound as well as an upper bound so that only + * valid task-issued commands are accepted here. */ + configASSERT( ( xCommandID >= tmrCOMMAND_START_DONT_TRACE ) && ( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) ); - if( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) + if( ( xCommandID >= tmrCOMMAND_START_DONT_TRACE ) && ( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) ) { if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) {