From 83c686c74402ebb64a1aed46f8ee43e6828f99c5 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Fri, 2 Feb 2024 23:37:36 +0800 Subject: [PATCH] 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 --- .../linux/include/freertos/portmacro.h | 18 ++----- .../FreeRTOS-Kernel-SMP/portable/linux/port.c | 4 +- .../riscv/include/freertos/portmacro.h | 35 ++++++++++---- .../FreeRTOS-Kernel-SMP/portable/riscv/port.c | 22 +++++---- .../portable/riscv/portasm.S | 4 ++ .../xtensa/include/freertos/portmacro.h | 47 ++++++++++--------- .../portable/xtensa/port.c | 30 +++++++----- .../portable/xtensa/portasm.S | 4 ++ .../FreeRTOS-Kernel-SMP/porting_notes.md | 41 ++++------------ components/freertos/Kconfig | 7 +-- .../config/include/freertos/FreeRTOSConfig.h | 7 +-- .../include/freertos/FreeRTOSConfig_arch.h | 2 +- .../include/freertos/FreeRTOSConfig_arch.h | 19 ++++---- .../include/freertos/FreeRTOSConfig_arch.h | 19 ++++---- .../freertos_tasks_c_additions.h | 2 + components/freertos/linker_common.lf | 2 + components/freertos/port_common.c | 10 ++++ components/freertos/port_systick.c | 2 + .../test_apps/freertos/port/test_fpu_in_isr.c | 4 +- .../freertos/port/test_fpu_in_task.c | 4 +- 20 files changed, 148 insertions(+), 135 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h index 9937260b05..f4ee05e14e 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h @@ -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 -------------------------- diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/port.c index c25bb0344a..aba16051f0 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/port.c @@ -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() ); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h index 754e2e3d24..2e252bb421 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h @@ -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 -------------------------- diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index 5af4c851f5..eb13f9e7f0 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -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 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S index a40244c33d..e3b4ccc59d 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S @@ -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 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h index 9198685e58..4ac4ffdb55 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h @@ -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 -------------------------- diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index f238dbc6e6..d5010bf708 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -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 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S index b472be7305..b05c44f65e 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S @@ -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 */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/porting_notes.md b/components/freertos/FreeRTOS-Kernel-SMP/porting_notes.md index 86504067bf..a9e7fb1b45 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/porting_notes.md +++ b/components/freertos/FreeRTOS-Kernel-SMP/porting_notes.md @@ -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 - diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 48407ceae9..f82ac3cd44 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -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" diff --git a/components/freertos/config/include/freertos/FreeRTOSConfig.h b/components/freertos/config/include/freertos/FreeRTOSConfig.h index 399f69d1d4..314051f1bf 100644 --- a/components/freertos/config/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/config/include/freertos/FreeRTOSConfig.h @@ -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 @@ -290,4 +291,4 @@ /* portNUM_PROCESSORS is deprecated and will be removed in ESP-IDF v6.0 (IDF-8785) * Please use the Kconfig option CONFIG_FREERTOS_NUMBER_OF_CORES instead. */ -#define portNUM_PROCESSORS configNUMBER_OF_CORES +#define portNUM_PROCESSORS configNUMBER_OF_CORES diff --git a/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h b/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h index 8c356eb4bc..7eb4e33c77 100644 --- a/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h +++ b/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h @@ -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 -------------------------- */ diff --git a/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h b/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h index b46fbbb4fa..198720a577 100644 --- a/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h +++ b/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h @@ -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,9 +41,13 @@ * - 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. */ -#define configINIT_TLS_BLOCK( xTLSBlock ) esp_reent_init( &( xTLSBlock ) ) +#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 ) ) +#define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) ) #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 diff --git a/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h b/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h index 0b3b1c8161..30210fee35 100644 --- a/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h +++ b/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h @@ -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,9 +68,13 @@ * - 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. */ -#define configINIT_TLS_BLOCK( xTLSBlock ) esp_reent_init( &( xTLSBlock ) ) +#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 ) ) +#define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) ) #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index 76317c2028..38bd6ac9df 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -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 ------------------------------------------------- */ diff --git a/components/freertos/linker_common.lf b/components/freertos/linker_common.lf index 80c25639d8..8e3f63030b 100644 --- a/components/freertos/linker_common.lf +++ b/components/freertos/linker_common.lf @@ -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) # ------------------------------------------------------------------------------------------------------------------ diff --git a/components/freertos/port_common.c b/components/freertos/port_common.c index 3e322c9772..0ac795ab82 100644 --- a/components/freertos/port_common.c +++ b/components/freertos/port_common.c @@ -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) diff --git a/components/freertos/port_systick.c b/components/freertos/port_systick.c index ea6a72bdb7..094fac1e65 100644 --- a/components/freertos/port_systick.c +++ b/components/freertos/port_systick.c @@ -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 ) /* diff --git a/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c b/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c index 5bdbc1375b..f86bec14ac 100644 --- a/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c +++ b/components/freertos/test_apps/freertos/port/test_fpu_in_isr.c @@ -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(); diff --git a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c index b472713d4c..6c52f314d9 100644 --- a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c +++ b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c @@ -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();