feat(freertos/smp): Update ports to support Amazon FreeRTOS v11.0.1

- vTaskPreemptionDisable()/vTaskPreemptionEnable() are no longer available in
single-core builds.
- xTaskIncrementTick() calls must now be wrapped by critical section
- Minimal Idle Task renamed to Passive Idle Task
- Port critical section APIs updated
This commit is contained in:
Darian Leung 2024-02-02 23:37:36 +08:00
parent 888678d102
commit 83c686c744
No known key found for this signature in database
GPG Key ID: 8AC9127B487AA4EF
20 changed files with 148 additions and 135 deletions

View File

@ -6,7 +6,7 @@
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* 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
@ -110,15 +110,16 @@ BaseType_t xPortCheckIfInISR(void);
// ------------------ Critical Sections --------------------
#if ( configNUMBER_OF_CORES > 1 )
/*
These are always called with interrupts already disabled. We simply need to get/release the spinlocks
*/
extern portMUX_TYPE port_xTaskLock;
extern portMUX_TYPE port_xISRLock;
void vPortTakeLock( portMUX_TYPE *lock );
void vPortReleaseLock( portMUX_TYPE *lock );
#endif /* configNUMBER_OF_CORES > 1 */
// ---------------------- Yielding -------------------------
@ -151,18 +152,9 @@ void vPortCleanUpTCB ( void *pxTCB );
#define portDISABLE_INTERRUPTS() xPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask(0)
#define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x)
// ------------------ Critical Sections --------------------
#define portGET_TASK_LOCK() vPortTakeLock(&port_xTaskLock)
#define portRELEASE_TASK_LOCK() vPortReleaseLock(&port_xTaskLock)
#define portGET_ISR_LOCK() vPortTakeLock(&port_xISRLock)
#define portRELEASE_ISR_LOCK() vPortReleaseLock(&port_xISRLock)
//Critical sections used by FreeRTOS SMP
extern void vTaskEnterCritical( void );
extern void vTaskExitCritical( void );
#define portENTER_CRITICAL_SMP() vTaskEnterCritical();
#define portEXIT_CRITICAL_SMP() vTaskExitCritical();
@ -286,8 +278,8 @@ void vPortExitCriticalIDF(void);
// ---------------------- Yielding -------------------------
// Added for backward compatibility with IDF
#define portYIELD_WITHIN_API() vTaskYieldWithinAPI()
extern void vPortYield( void );
#define portYIELD() vPortYield()
// ----------------------- System --------------------------

View File

@ -298,7 +298,7 @@ void vPortYieldFromISR( void )
xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
vTaskSwitchContext(xPortGetCoreID());
vTaskSwitchContext();
xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
@ -419,7 +419,7 @@ static void vPortSystemTickHandler( int sig )
#if ( configUSE_PREEMPTION == 1 )
if (xSwitchRequired == pdTRUE) {
/* Select Next Task. */
vTaskSwitchContext(xPortGetCoreID());
vTaskSwitchContext();
pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,15 +10,28 @@
/* Macros used instead ofsetoff() for better performance of interrupt handler */
#if CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES
/*
pxTopOfStack (4) +
xStateListItem (28) +
xEventListItem (28) +
uxPriority (4)
*/
#define PORT_OFFSET_PX_STACK 0x40
#else
/*
pxTopOfStack (4) +
xStateListItem (20) +
xEventListItem (20) +
uxPriority (4)
*/
#define PORT_OFFSET_PX_STACK 0x30
#endif /* #if CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES */
#define PORT_OFFSET_PX_END_OF_STACK (PORT_OFFSET_PX_STACK + \
/* void * pxDummy6 */ 4 + \
/* BaseType_t xDummy23[ 2 ] */ 8 + \
/* uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ] */ CONFIG_FREERTOS_MAX_TASK_NAME_LEN + \
/* BaseType_t xDummy24 */ 4)
#define PORT_OFFSET_PX_END_OF_STACK ( \
PORT_OFFSET_PX_STACK \
+ 4 /* StackType_t * pxStack */ \
+ CONFIG_FREERTOS_MAX_TASK_NAME_LEN /* pcTaskName[ configMAX_TASK_NAME_LEN ] */ \
)
#ifndef __ASSEMBLER__
@ -102,15 +115,16 @@ BaseType_t xPortCheckIfInISR(void);
// ------------------ Critical Sections --------------------
#if ( configNUMBER_OF_CORES > 1 )
/*
These are always called with interrupts already disabled. We simply need to get/release the spinlocks
*/
extern portMUX_TYPE port_xTaskLock;
extern portMUX_TYPE port_xISRLock;
void vPortTakeLock( portMUX_TYPE *lock );
void vPortReleaseLock( portMUX_TYPE *lock );
#endif /* configNUMBER_OF_CORES > 1 */
// ---------------------- Yielding -------------------------
@ -175,11 +189,12 @@ void vPortTCBPreDeleteHook( void *pxTCB );
// ------------------ Critical Sections --------------------
#if ( configNUMBER_OF_CORES > 1 )
#define portGET_TASK_LOCK() vPortTakeLock(&port_xTaskLock)
#define portRELEASE_TASK_LOCK() vPortReleaseLock(&port_xTaskLock)
#define portGET_ISR_LOCK() vPortTakeLock(&port_xISRLock)
#define portRELEASE_ISR_LOCK() vPortReleaseLock(&port_xISRLock)
#endif /* configNUMBER_OF_CORES > 1 */
//Critical sections used by FreeRTOS SMP
extern void vTaskEnterCritical( void );
@ -314,8 +329,8 @@ static inline bool IRAM_ATTR xPortCanYield(void)
return (threshold <= 1);
}
// Added for backward compatibility with IDF
#define portYIELD_WITHIN_API() vTaskYieldWithinAPI()
// Defined even for configNUMBER_OF_CORES > 1 for IDF compatibility
#define portYIELD_WITHIN_API() esp_crosscore_int_send_yield(xPortGetCoreID())
// ----------------------- System --------------------------

View File

@ -170,6 +170,7 @@ BaseType_t xPortCheckIfInISR(void)
// ------------------ Critical Sections --------------------
#if ( configNUMBER_OF_CORES > 1 )
void IRAM_ATTR vPortTakeLock( portMUX_TYPE *lock )
{
spinlock_acquire( lock, portMUX_NO_TIMEOUT);
@ -179,6 +180,7 @@ void IRAM_ATTR vPortReleaseLock( portMUX_TYPE *lock )
{
spinlock_release( lock );
}
#endif /* configNUMBER_OF_CORES > 1 */
// ---------------------- Yielding -------------------------
@ -486,21 +488,21 @@ void vApplicationTickHook( void )
#endif
extern void esp_vApplicationIdleHook(void);
#if CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK
#if CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
/*
By default, the port uses vApplicationMinimalIdleHook() to run IDF style idle
hooks. However, users may also want to provide their own vApplicationMinimalIdleHook().
In this case, we use to -Wl,--wrap option to wrap the user provided vApplicationMinimalIdleHook()
By default, the port uses vApplicationPassiveIdleHook() to run IDF style idle
hooks. However, users may also want to provide their own vApplicationPassiveIdleHook().
In this case, we use to -Wl,--wrap option to wrap the user provided vApplicationPassiveIdleHook()
*/
extern void __real_vApplicationMinimalIdleHook( void );
void __wrap_vApplicationMinimalIdleHook( void )
extern void __real_vApplicationPassiveIdleHook( void );
void __wrap_vApplicationPassiveIdleHook( void )
{
esp_vApplicationIdleHook(); //Run IDF style hooks
__real_vApplicationMinimalIdleHook(); //Call the user provided vApplicationMinimalIdleHook()
__real_vApplicationPassiveIdleHook(); //Call the user provided vApplicationPassiveIdleHook()
}
#else // CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK
void vApplicationMinimalIdleHook( void )
#else // CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
void vApplicationPassiveIdleHook( void )
{
esp_vApplicationIdleHook(); //Run IDF style hooks
}
#endif // CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK
#endif // CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK

View File

@ -7,6 +7,10 @@
#include "portmacro.h"
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
#include "esp_private/hw_stack_guard.h"
#endif
#if CONFIG_FREERTOS_UNICORE
#define pxCurrentTCBs pxCurrentTCB
#endif
.global uxInterruptNesting

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -100,15 +100,16 @@ BaseType_t xPortCheckIfInISR(void);
UBaseType_t uxPortEnterCriticalFromISR( void );
void vPortExitCriticalFromISR( UBaseType_t level );
#if ( configNUMBER_OF_CORES > 1 )
/*
These are always called with interrupts already disabled. We simply need to get/release the spinlocks
*/
extern portMUX_TYPE port_xTaskLock;
extern portMUX_TYPE port_xISRLock;
void vPortTakeLock( portMUX_TYPE *lock );
void vPortReleaseLock( portMUX_TYPE *lock );
#endif /* configNUMBER_OF_CORES > 1 */
// ---------------------- Yielding -------------------------
@ -151,35 +152,42 @@ void vPortTCBPreDeleteHook( void *pxTCB );
// --------------------- Interrupts ------------------------
#define portDISABLE_INTERRUPTS() ({ \
#define portSET_INTERRUPT_MASK() ({ \
unsigned int prev_level = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); \
portbenchmarkINTERRUPT_DISABLE(); \
prev_level = ((prev_level >> XCHAL_PS_INTLEVEL_SHIFT) & XCHAL_PS_INTLEVEL_MASK); \
prev_level; \
})
#define portENABLE_INTERRUPTS() ({ \
portbenchmarkINTERRUPT_RESTORE(0); \
XTOS_SET_INTLEVEL(0); \
})
#define portSET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK()
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK()
/*
Note: XTOS_RESTORE_INTLEVEL() will overwrite entire PS register on XEA2. So we need ot make the value INTLEVEL field ourselves
Note: XTOS_RESTORE_INTLEVEL() will overwrite entire PS register on XEA2. So we need to set the value of the INTLEVEL field ourselves
*/
#define portRESTORE_INTERRUPTS(x) ({ \
#define portCLEAR_INTERRUPT_MASK(x) ({ \
unsigned int ps_reg; \
RSR(PS, ps_reg); \
ps_reg = (ps_reg & ~XCHAL_PS_INTLEVEL_MASK); \
ps_reg |= ((x << XCHAL_PS_INTLEVEL_SHIFT) & XCHAL_PS_INTLEVEL_MASK); \
XTOS_RESTORE_INTLEVEL(ps_reg); \
})
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK(x)
#define portENABLE_INTERRUPTS() ({ \
portbenchmarkINTERRUPT_RESTORE(0); \
XTOS_SET_INTLEVEL(0); \
})
/* Compatibility */
#define portRESTORE_INTERRUPTS(x) portCLEAR_INTERRUPT_MASK(x)
// ------------------ Critical Sections --------------------
#if ( configNUMBER_OF_CORES > 1 )
#define portGET_TASK_LOCK() vPortTakeLock(&port_xTaskLock)
#define portRELEASE_TASK_LOCK() vPortReleaseLock(&port_xTaskLock)
#define portGET_ISR_LOCK() vPortTakeLock(&port_xISRLock)
#define portRELEASE_ISR_LOCK() vPortReleaseLock(&port_xISRLock)
#endif /* configNUMBER_OF_CORES > 1 */
//Critical sections used by FreeRTOS SMP
extern void vTaskEnterCritical( void );
@ -195,17 +203,10 @@ extern void vTaskExitCritical( void );
#define portEXIT_CRITICAL(...) CHOOSE_MACRO_VA_ARG(portEXIT_CRITICAL_IDF, portEXIT_CRITICAL_SMP, ##__VA_ARGS__)(__VA_ARGS__)
#endif
#define portSET_INTERRUPT_MASK_FROM_ISR() ({ \
unsigned int cur_level; \
RSR(PS, cur_level); \
cur_level = (cur_level & XCHAL_PS_INTLEVEL_MASK) >> XCHAL_PS_INTLEVEL_SHIFT; \
vTaskEnterCritical(); \
cur_level; \
})
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) ({ \
vTaskExitCritical(); \
portRESTORE_INTERRUPTS(x); \
})
extern UBaseType_t vTaskEnterCriticalFromISR( void );
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
#define portEXIT_CRITICAL_FROM_ISR(x) vTaskExitCriticalFromISR(x)
// ---------------------- Yielding -------------------------
@ -356,8 +357,8 @@ static inline bool IRAM_ATTR xPortCanYield(void)
return ((ps_reg & PS_INTLEVEL_MASK) == 0);
}
// Added for backward compatibility with IDF
#define portYIELD_WITHIN_API() vTaskYieldWithinAPI()
// Defined even for configNUMBER_OF_CORES > 1 for IDF compatibility
#define portYIELD_WITHIN_API() esp_crosscore_int_send_yield(xPortGetCoreID())
// ----------------------- System --------------------------

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -63,7 +63,7 @@ const DRAM_ATTR uint32_t offset_pxEndOfStack = offsetof(StaticTask_t, pxDummy8);
const DRAM_ATTR uint32_t offset_cpsa = XT_CP_SIZE; /* Offset to start of the CPSA area on the stack. See uxInitialiseStackCPSA(). */
#if configNUM_CORES > 1
/* Offset to TCB_t.uxCoreAffinityMask member. Used to pin unpinned tasks that use the FPU. */
const DRAM_ATTR uint32_t offset_uxCoreAffinityMask = offsetof(StaticTask_t, uxDummy25);
const DRAM_ATTR uint32_t offset_uxCoreAffinityMask = offsetof(StaticTask_t, uxDummy26);
#if configUSE_CORE_AFFINITY != 1
#error "configUSE_CORE_AFFINITY must be 1 on multicore targets with coprocessor support"
#endif
@ -72,9 +72,11 @@ const DRAM_ATTR uint32_t offset_uxCoreAffinityMask = offsetof(StaticTask_t, uxDu
volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates whether scheduler is running on a per-core basis
unsigned int port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit
#if ( configNUMBER_OF_CORES > 1 )
//FreeRTOS SMP Locks
portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
#endif /* configNUMBER_OF_CORES > 1 */
/* ------------------------------------------------ IDF Compatibility --------------------------------------------------
* - These need to be defined for IDF to compile
@ -204,6 +206,7 @@ BaseType_t xPortCheckIfInISR(void)
// ------------------ Critical Sections --------------------
#if ( configNUMBER_OF_CORES > 1 )
void vPortTakeLock( portMUX_TYPE *lock )
{
spinlock_acquire( lock, portMUX_NO_TIMEOUT);
@ -213,6 +216,7 @@ void vPortReleaseLock( portMUX_TYPE *lock )
{
spinlock_release( lock );
}
#endif /* configNUMBER_OF_CORES > 1 */
// ---------------------- Yielding -------------------------
@ -262,7 +266,7 @@ static void vPortCleanUpCoprocArea( void *pxTCB )
uxCoprocArea = STACKPTR_ALIGN_DOWN(16, uxCoprocArea - XT_CP_SIZE);
/* Extract core ID from the affinity mask */
xTargetCoreID = ( ( StaticTask_t * ) pxTCB )->uxDummy25 ;
xTargetCoreID = ( ( StaticTask_t * ) pxTCB )->uxDummy26;
xTargetCoreID = ( BaseType_t ) __builtin_ffs( ( int ) xTargetCoreID );
assert( xTargetCoreID >= 1 ); // __builtin_ffs always returns first set index + 1
xTargetCoreID -= 1;
@ -667,21 +671,21 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, c
#endif
extern void esp_vApplicationIdleHook(void);
#if CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK
#if CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
/*
By default, the port uses vApplicationMinimalIdleHook() to run IDF style idle
hooks. However, users may also want to provide their own vApplicationMinimalIdleHook().
In this case, we use to -Wl,--wrap option to wrap the user provided vApplicationMinimalIdleHook()
By default, the port uses vApplicationPassiveIdleHook() to run IDF style idle
hooks. However, users may also want to provide their own vApplicationPassiveIdleHook().
In this case, we use to -Wl,--wrap option to wrap the user provided vApplicationPassiveIdleHook()
*/
extern void __real_vApplicationMinimalIdleHook( void );
void __wrap_vApplicationMinimalIdleHook( void )
extern void __real_vApplicationPassiveIdleHook( void );
void __wrap_vApplicationPassiveIdleHook( void )
{
esp_vApplicationIdleHook(); //Run IDF style hooks
__real_vApplicationMinimalIdleHook(); //Call the user provided vApplicationMinimalIdleHook()
__real_vApplicationPassiveIdleHook(); //Call the user provided vApplicationPassiveIdleHook()
}
#else // CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK
void vApplicationMinimalIdleHook( void )
#else // CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
void vApplicationPassiveIdleHook( void )
{
esp_vApplicationIdleHook(); //Run IDF style hooks
}
#endif // CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK
#endif // CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK

View File

@ -33,6 +33,10 @@
#define TOPOFSTACK_OFFS 0x00 /* StackType_t *pxTopOfStack */
#if CONFIG_FREERTOS_UNICORE
#define pxCurrentTCBs pxCurrentTCB
#endif
.extern pxCurrentTCBs
#if XCHAL_CP_NUM > 0
/* Offsets used to get a task's coprocessor save area (CPSA) from its TCB */

View File

@ -1,20 +1,17 @@
# Overview
This document outlines some useful notes about
- The porting of SMP FreeRTOS to ESP-IDF
- And the difference between IDF FreeRTOS and SMP FreeRTOS
This document outlines some notes regarding the Amazon AMP FreeRTOS port in ESP-IDF
# Terminology
The following terms will be used in this document to avoid confusion between the different FreeRTOS versions currently in ESP-IDF
- SMP FreeRTOS: The SMP branch of the FreeRTOS kernel found [here](https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/smp)
- SMP FreeRTOS: An SMP capable release of the FreeRTOS kernel described [here](https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/smp)
- IDF FreeRTOS: The version of FreeRTOS used in mainline ESP-IDF that contained custom modifications to support SMP features specific to the ESP chips.
# Organization
This directory contains a copy of SMP FreeRTOS based off of upstream commit [8128208](https://github.com/FreeRTOS/FreeRTOS-Kernel/commit/8128208bdee1f997f83cae631b861f36aeea9b1f)
This directory contains a copy of upstream [v11.0.1](https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/V11.0.1) FreeRTOS which is SMP capable.
- IDF FreeRTOS remains in `components/freertos/FreeRTOS-Kernel`
- SMP FreeRTOS is entirely contained in `components/freertos/FreeRTOS-Kernel-SMP`
@ -104,15 +101,15 @@ IDF FreeRTOS:
SMP FreeRTOS:
- There are now two types of idle task functions. The `prvIdleTask()` and `prvMinimalIdleTask()`
- `prvMinimalIdleTask()` simply calls the `vApplicationMinimalIdleHook()`
- `prvIdleTask()` calls `prvCheckTasksWaitingTermination()`, `vApplicationIdleHook()`, `vApplicationMinimalIdleHook()`, and handles tickless idle.
- On an N core build, one `prvIdleTask()` task is created and N-1 `prvMinimalIdleTask()` tasks are created.
- There are now two types of idle task functions. The `prvIdleTask()` and `prvPassiveIdleTask()`
- `prvPassiveIdleTask()` simply calls the `vApplicationPassiveIdleHook()`
- `prvIdleTask()` calls `prvCheckTasksWaitingTermination()`, `vApplicationIdleHook()`, `vApplicationPassiveIdleHook()`, and handles tickless idling.
- On an N core build, one `prvIdleTask()` task is created and N-1 `prvPassiveIdleTask()` tasks are created.
- The created idle tasks are all unpinned. The idle tasks are run on a "first come first serve" basis meaning when a core goes idle, it selects whatever available idle task it can run.
Changes Made:
- The `esp_vApplicationIdleHook()` is now called from `vApplicationMinimalIdleHook()` since every idle task calls the `vApplicationMinimalIdleHook()`.
- The `esp_vApplicationIdleHook()` is now called from `vApplicationPassiveIdleHook()` since every idle task calls the `vApplicationPassiveIdleHook()`.
- Since the idle tasks are unpinned, the task WDT has been updated to use the "User" feature. Thus, feeding the task watchdog now tracks which "core" has fed the task WDT instead of which specific idle task has fed.
- Since `prvIdleTask()` is solely responsible for calling `prvCheckTasksWaitingTermination()` but can run on any core, multiple IDF cleanup routines are now routed through `portCLEAN_UP_TCB()`
- FPU registers of a task are now cleaned up via `portCLEAN_UP_TCB() -> vPortCleanUpCoprocArea()` and can clean FPU save areas across cores.
@ -169,25 +166,3 @@ IDF FreeRTOS added multiple features/APIs that are specific to IDF. For SMP Free
- If TLSP deletion callbacks are used, `configNUM_THREAD_LOCAL_STORAGE_POINTERS` will be doubled (in order to store the callback pointers in the same array as the TLSPs themselves)
- `vTaskSetThreadLocalStoragePointerAndDelCallback()` moved to `freertos_tasks_c_additions.h`/`idf_additions.h`
- Deletion callbacks invoked from the main idle task via `portCLEAN_UP_TCB()`
### `xTaskGetCurrentTaskHandleForCPU()`
- Convenience function to the get current task of a particular CPU
- Moved to `freertos_tasks_c_additions.h`/`idf_additions.h` for now
Todo: Check if this can be upstreamed
### `xTaskGetIdleTaskHandleForCPU()`
- Currently moved to `freertos_tasks_c_additions.h`/`idf_additions.h`
Todo: This needs to be deprecated as there is no longer the concept of idle tasks pinned to a particular CPU
### `xTaskGetAffinity()`
- Returns what core a task is pinned to, and not the task's affinity mask.
- Moved to `freertos_tasks_c_additions.h`/`idf_additions.h` and simple wraps `vTaskCoreAffinityGet()`
- If the task's affinity mask has more than one permissible core, we simply return `tskNO_AFFINITY` even if the task is not completely unpinned.
Todo: This needs to be deprecated and users should call `vTaskCoreAffinityGet()` instead

View File

@ -3,6 +3,7 @@ menu "FreeRTOS"
menu "Kernel"
# Upstream FreeRTOS configurations go here
config FREERTOS_SMP
bool "Run the Amazon SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)"
depends on !IDF_TARGET_ESP32P4 #TODO: IDF-8113: Enable P4 support on AMZ SMP
@ -116,7 +117,7 @@ menu "FreeRTOS"
- The FreeRTOS idle hook is NOT the same as the ESP-IDF Idle Hook, but both can be enabled
simultaneously.
config FREERTOS_USE_MINIMAL_IDLE_HOOK
config FREERTOS_USE_PASSIVE_IDLE_HOOK
bool "Use FreeRTOS minimal idle hook"
depends on FREERTOS_SMP
default n
@ -126,8 +127,8 @@ menu "FreeRTOS"
Note:
- The application must provide the hook function ``void vApplicationMinimalIdleHook( void );``
- ``vApplicationMinimalIdleHook()`` is called from FreeRTOS minimal idle task(s)
- The application must provide the hook function ``void vApplicationPassiveIdleHook( void );``
- ``vApplicationPassiveIdleHook()`` is called from FreeRTOS minimal idle task(s)
config FREERTOS_USE_TICK_HOOK
bool "configUSE_TICK_HOOK"

View File

@ -262,10 +262,11 @@
* - All Amazon SMP FreeRTOS specific configurations
* ------------------------------------------------------------------------------------------------------------------ */
#if CONFIG_FREERTOS_SMP
#if CONFIG_FREERTOS_SMP && ( CONFIG_FREERTOS_NUMBER_OF_CORES > 1 )
#define configUSE_CORE_AFFINITY 1
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_TASK_PREEMPTION_DISABLE 1
#endif /* CONFIG_FREERTOS_SMP */
#endif /* CONFIG_FREERTOS_SMP && ( CONFIG_FREERTOS_NUMBER_OF_CORES > 1 ) */
/* -------------------------------------------------- IDF FreeRTOS -----------------------------------------------------
* - All IDF FreeRTOS specific configurations

View File

@ -31,7 +31,7 @@
/* ---------------- Amazon SMP FreeRTOS -------------------- */
#if CONFIG_FREERTOS_SMP
#define configUSE_MINIMAL_IDLE_HOOK 0 /* Not implemented yet, TODO IDF-6654 */
#define configUSE_PASSIVE_IDLE_HOOK 0 /* Not implemented yet, TODO IDF-6654 */
#endif
/* ----------------------- System -------------------------- */

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -27,15 +27,10 @@
/* ---------------- Amazon SMP FreeRTOS -------------------- */
#if CONFIG_FREERTOS_SMP
#define configUSE_CORE_AFFINITY 1
/* This is always enabled to call IDF style idle hooks, by can be "--Wl,--wrap"
* if users enable CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK. */
#define configUSE_MINIMAL_IDLE_HOOK 1
/* IDF Newlib supports dynamic reentrancy. We provide our own __getreent()
* function. */
#define configNEWLIB_REENTRANT_IS_DYNAMIC 1
* if users enable CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK. */
#define configUSE_PASSIVE_IDLE_HOOK 1
#endif
/* ----------------------- System -------------------------- */
@ -46,7 +41,11 @@
* - We simply provide our own INIT and DEINIT functions
* - We set "SET" to a blank macro since there is no need to set the reentrancy
* pointer. All newlib functions calls __getreent. */
#if CONFIG_FREERTOS_SMP
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) esp_reent_init( &( xTLSBlock ) )
#else /* CONFIG_FREERTOS_SMP */
#define configINIT_TLS_BLOCK( xTLSBlock ) esp_reent_init( &( xTLSBlock ) )
#endif /* CONFIG_FREERTOS_SMP */
#define configSET_TLS_BLOCK( xTLSBlock )
#define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) )

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -54,15 +54,10 @@
/* ---------------- Amazon SMP FreeRTOS -------------------- */
#if CONFIG_FREERTOS_SMP
#define configUSE_CORE_AFFINITY 1
/* This is always enabled to call IDF style idle hooks, by can be "--Wl,--wrap"
* if users enable CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK. */
#define configUSE_MINIMAL_IDLE_HOOK 1
/* IDF Newlib supports dynamic reentrancy. We provide our own __getreent()
* function. */
#define configNEWLIB_REENTRANT_IS_DYNAMIC 1
* if users enable CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK. */
#define configUSE_PASSIVE_IDLE_HOOK 1
#endif
/* ----------------------- System -------------------------- */
@ -73,7 +68,11 @@
* - We simply provide our own INIT and DEINIT functions
* - We set "SET" to a blank macro since there is no need to set the reentrancy
* pointer. All newlib functions calls __getreent. */
#if CONFIG_FREERTOS_SMP
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) esp_reent_init( &( xTLSBlock ) )
#else /* CONFIG_FREERTOS_SMP */
#define configINIT_TLS_BLOCK( xTLSBlock ) esp_reent_init( &( xTLSBlock ) )
#endif /* CONFIG_FREERTOS_SMP */
#define configSET_TLS_BLOCK( xTLSBlock )
#define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) )

View File

@ -29,7 +29,9 @@
*/
_Static_assert( offsetof( StaticTask_t, pxDummy6 ) == offsetof( TCB_t, pxStack ) );
_Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfStack ) );
#if !CONFIG_IDF_TARGET_LINUX // Disabled for linux builds due to differences in types
_Static_assert( tskNO_AFFINITY == ( BaseType_t ) CONFIG_FREERTOS_NO_AFFINITY, "CONFIG_FREERTOS_NO_AFFINITY must be the same as tskNO_AFFINITY" );
#endif
/* ------------------------------------------------- Kernel Control ------------------------------------------------- */

View File

@ -88,6 +88,8 @@ entries:
port_common (noflash_text) # Default all functions to internal RAM
if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y:
port_common:vApplicationGetIdleTaskMemory (default)
if FREERTOS_SMP = y && FREERTOS_UNICORE = n:
port_common:vApplicationGetPassiveIdleTaskMemory (default)
port_common:vApplicationGetTimerTaskMemory (default)
# ------------------------------------------------------------------------------------------------------------------

View File

@ -57,6 +57,16 @@ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
#if ( ( CONFIG_FREERTOS_SMP ) && ( configNUMBER_OF_CORES > 1 ) )
void vApplicationGetPassiveIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize,
BaseType_t xPassiveIdleTaskIndex)
{
vApplicationGetIdleTaskMemory(ppxIdleTaskTCBBuffer, ppxIdleTaskStackBuffer, pulIdleTaskStackSize);
}
#endif /* ( ( CONFIG_FREERTOS_SMP ) && ( configNUMBER_OF_CORES > 1 ) ) */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)

View File

@ -201,6 +201,7 @@ BaseType_t xPortSysTickHandler(void)
// Call FreeRTOS Increment tick function
BaseType_t xSwitchRequired;
#if CONFIG_FREERTOS_SMP
UBaseType_t uxSavedStatus = taskENTER_CRITICAL_FROM_ISR();
// Amazon SMP FreeRTOS requires that only core 0 calls xTaskIncrementTick()
#if ( configNUM_CORES > 1 )
if (portGET_CORE_ID() == 0) {
@ -211,6 +212,7 @@ BaseType_t xPortSysTickHandler(void)
#else /* configNUM_CORES > 1 */
xSwitchRequired = xTaskIncrementTick();
#endif /* configNUM_CORES > 1 */
taskEXIT_CRITICAL_FROM_ISR(uxSavedStatus);
#else /* !CONFIG_FREERTOS_SMP */
#if ( configNUM_CORES > 1 )
/*

View File

@ -109,7 +109,7 @@ Expected:
static void unpinned_task(void *arg)
{
// Disable scheduling/preemption to make sure the current task doesn't switch cores
#if CONFIG_FREERTOS_SMP
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
vTaskPreemptionDisable(NULL);
#else
vTaskSuspendAll();
@ -140,7 +140,7 @@ static void unpinned_task(void *arg)
#endif
#endif // !CONFIG_FREERTOS_UNICORE
// Reenable scheduling/preemption
#if CONFIG_FREERTOS_SMP
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
vTaskPreemptionEnable(NULL);
#else
xTaskResumeAll();

View File

@ -130,7 +130,7 @@ Expected:
static void unpinned_task(void *arg)
{
// Disable scheduling/preemption to make sure current core ID doesn't change
#if CONFIG_FREERTOS_SMP
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
vTaskPreemptionDisable(NULL);
#else
vTaskSuspendAll();
@ -166,7 +166,7 @@ static void unpinned_task(void *arg)
#endif
#endif // !CONFIG_FREERTOS_UNICORE
// Reenable scheduling/preemption
#if CONFIG_FREERTOS_SMP
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
vTaskPreemptionEnable(NULL);
#else
xTaskResumeAll();