diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index 6d61e46c618..621b226cdee 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -63,6 +63,9 @@ _Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK BaseType_t uxSchedulerRunning = 0; // Duplicate of xSchedulerRunning, accessible to port files volatile UBaseType_t uxInterruptNesting = 0; +#if configNUM_CORES > 1 +volatile unsigned port_uxCoreStartupDone[portNUM_PROCESSORS] = {0}; // Indicates whether the core has completed its startup sequence +#endif portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED; volatile BaseType_t xPortSwitchFlag = 0; @@ -291,7 +294,9 @@ BaseType_t xPortStartScheduler(void) uxInterruptNesting = 0; port_uxCriticalNestingIDF = 0; uxSchedulerRunning = 0; - +#if configNUM_CORES > 1 + port_uxCoreStartupDone[xPortGetCoreID()] = 0; +#endif /* Setup the hardware to generate the tick. */ vPortSetupTimer(); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S index f68adf012d7..36ee48b081e 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,9 @@ .global pxCurrentTCBs .global vTaskSwitchContext .global xPortSwitchFlag +#if ( configNUM_CORES > 1 ) + .global port_uxCoreStartupDone +#endif #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD .global xIsrStack .global port_offset_pxStack @@ -137,6 +140,16 @@ no_switch: lw t0, pxCurrentTCBs lw sp, 0x0(t0) +#if ( configNUM_CORES > 1 ) + /* Indicate that this CPU has completed startup */ + la t1, port_uxCoreStartupDone /* t1 = &port_uxCoreStartupDone */ + csrr a1, mhartid /* a1 = coreID */ + slli a1, a1, 2 /* a1 = coreID * 4 */ + add t1, t1, a1 /* t1 = &port_uxCoreStartupDone[coreID] // a1 contains coreID * 4 */ + li a1, 1 /* a1 = 1 */ + sw a1, 0(t1) /* port_uxCoreStartupDone[coreID] = 1 */ +#endif /* ( configNUM_CORES > 1 ) */ + #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* esp_hw_stack_guard_set_bounds(pxCurrentTCBs[0]->pxStack, * pxCurrentTCBs[0]->pxEndOfStack); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index 84f751c663c..d96180c422d 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -76,6 +76,7 @@ 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 +volatile unsigned port_uxCoreStartupDone[portNUM_PROCESSORS] = {0}; // Indicates whether the core has completed its startup sequence #if ( configNUMBER_OF_CORES > 1 ) //FreeRTOS SMP Locks portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED; @@ -333,7 +334,10 @@ BaseType_t xPortStartScheduler( void ) /* Setup the hardware to generate the tick. */ vPortSetupTimer(); - port_xSchedulerRunning[xPortGetCoreID()] = 1; + /* Initialize all kernel state tracking variables */ + BaseType_t coreID = xPortGetCoreID(); + port_xSchedulerRunning[coreID] = 1; + port_uxCoreStartupDone[coreID] = 0; #if configNUM_CORES > 1 // Workaround for non-thread safe multi-core OS startup (see IDF-4524) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S index b05c44f65ea..7e41f44bfda 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2025 Espressif Systems (Shanghai) CO LTD */ /* * Copyright (c) 2015-2019 Cadence Design Systems, Inc. @@ -284,7 +284,7 @@ _frxt_int_exit: * Manages the tick timer and calls xPortSysTickHandler() every tick. * See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h. * -* Callable from C (obeys ABI conventions). Implemented in assmebly code for performance. +* Callable from C (obeys ABI conventions). Implemented in assembly code for performance. * ********************************************************************************************************** */ @@ -373,7 +373,7 @@ _frxt_timer_int: * _frxt_tick_timer_init * void _frxt_tick_timer_init(void) * -* Initialize timer and timer interrrupt handler (_xt_tick_divisor_init() has already been been called). +* Initialize timer and timer interrupt handler (_xt_tick_divisor_init() has already been been called). * Callable from C (obeys ABI conventions on entry). * ********************************************************************************************************** @@ -463,6 +463,15 @@ _frxt_dispatch: l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */ s32i a3, a2, 0 +#if ( configNUM_CORES > 1 ) + /* Indicate that this CPU has completed startup. */ + movi a2, port_uxCoreStartupDone /* a2 = &port_uxCoreStartupDone */ + getcoreid a3 + addx4 a2, a3, a2 /* a2 = &port_uxCoreStartupDone[coreid] */ + movi a3, 1 /* a3 = 1 */ + s32i a3, a2, 0 /* port_uxCoreStartupDone[coreid] = 1 */ +#endif /* ( configNUM_CORES > 1 ) */ + /* Determine the type of stack frame. */ l32i a2, sp, XT_STK_EXIT /* exit dispatcher or solicited flag */ bnez a2, .L_frxt_dispatch_stk diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 22a44e3e227..e6edd6a185f 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -99,6 +99,7 @@ volatile UBaseType_t port_uxInterruptNesting[portNUM_PROCESSORS] = {0}; // Inte volatile UBaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; volatile UBaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; volatile UBaseType_t xPortSwitchFlag[portNUM_PROCESSORS] = {0}; +volatile UBaseType_t port_uxCoreStartupDone[portNUM_PROCESSORS] = {0}; // Indicates whether the core has completed its startup sequence #if ( SOC_CPU_COPROC_NUM > 0 ) @@ -156,6 +157,7 @@ BaseType_t xPortStartScheduler(void) port_uxInterruptNesting[coreID] = 0; port_uxCriticalNesting[coreID] = 0; port_xSchedulerRunning[coreID] = 0; + port_uxCoreStartupDone[coreID] = 0; /* Initialize ISR Stack(s) */ for (int i = 0; i < portNUM_PROCESSORS; i++) { diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S index 3185bb4bcfa..be5b80e8a37 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S @@ -24,6 +24,7 @@ .global pxCurrentTCBs .global vTaskSwitchContext .global xPortSwitchFlag + .global port_uxCoreStartupDone #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD .global xIsrStackBottom .global esp_hw_stack_guard_monitor_stop @@ -857,6 +858,13 @@ restore_stack_pointer: lw sp, 0(a0) #endif /* ( configNUM_CORES > 1 ) */ +#if ( configNUM_CORES > 1 ) + /* Indicate that this CPU has completed startup */ + la t1, port_uxCoreStartupDone /* t1 = &port_uxCoreStartupDone */ + add t1, t1, s0 /* t1 = &port_uxCoreStartupDone[coreID] // s0 contains coreID * 4 */ + li a1, 1 /* a1 = 1 */ + sw a1, 0(t1) /* port_uxCoreStartupDone[coreID] = 1 */ +#endif /* ( configNUM_CORES > 1 ) */ #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* esp_hw_stack_guard_set_bounds(pxCurrentTCBs[0]->pxStack, diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c index 655fb4aa35d..558475de231 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c @@ -76,6 +76,7 @@ volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; +volatile unsigned port_uxCoreStartupDone[portNUM_PROCESSORS] = {0}; // Indicates whether the core has completed its startup sequence /* ******************************************************************************* @@ -110,7 +111,10 @@ BaseType_t xPortStartScheduler( void ) /* Setup the hardware to generate the tick. */ vPortSetupTimer(); - port_xSchedulerRunning[xPortGetCoreID()] = 1; + /* Initialize all kernel state tracking variables */ + BaseType_t coreID = xPortGetCoreID(); + port_xSchedulerRunning[coreID] = 1; + port_uxCoreStartupDone[coreID] = 0; // Windows contain references to the startup stack which will be reclaimed by the main task // Spill the windows to create a clean environment to ensure we do not carry over any such references diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S index 756fae8481e..ff9513dcc9b 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2025 Espressif Systems (Shanghai) CO LTD */ /* * Copyright (c) 2015-2019 Cadence Design Systems, Inc. @@ -457,6 +457,15 @@ _frxt_dispatch: l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */ s32i a3, a2, 0 +#if ( configNUM_CORES > 1 ) + /* Indicate that this CPU has completed startup. */ + movi a2, port_uxCoreStartupDone /* a2 = &port_uxCoreStartupDone */ + getcoreid a3 + addx4 a2, a3, a2 /* a2 = &port_uxCoreStartupDone[coreid] */ + movi a3, 1 /* a3 = 1 */ + s32i a3, a2, 0 /* port_uxCoreStartupDone[coreid] = 1 */ +#endif /* ( configNUM_CORES > 1 ) */ + /* Determine the type of stack frame. */ l32i a2, sp, XT_STK_EXIT /* exit dispatcher or solicited flag */ bnez a2, .L_frxt_dispatch_stk diff --git a/components/freertos/app_startup.c b/components/freertos/app_startup.c index 03f4a4f04ea..7c31557d357 100644 --- a/components/freertos/app_startup.c +++ b/components/freertos/app_startup.c @@ -108,7 +108,7 @@ void esp_startup_start_app_other_cores(void) } // Wait for CPU0 to start FreeRTOS before progressing - extern volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS]; + extern volatile unsigned port_xSchedulerRunning[CONFIG_FREERTOS_NUMBER_OF_CORES]; while (port_xSchedulerRunning[0] == 0) { ; } @@ -137,27 +137,27 @@ void esp_startup_start_app_other_cores(void) ESP_LOG_ATTR_TAG(MAIN_TAG, "main_task"); -#if !CONFIG_FREERTOS_UNICORE -static volatile bool s_other_cpu_startup_done = false; -static bool other_cpu_startup_idle_hook_cb(void) +/* This function has to guarantee that all CPUs have finished the FreeRTOS initialization +* and the startup stack is not in use. +*/ +static void wait_for_all_cores_ready(void) { - s_other_cpu_startup_done = true; - return true; +#if !CONFIG_FREERTOS_UNICORE + extern volatile unsigned port_uxCoreStartupDone[CONFIG_FREERTOS_NUMBER_OF_CORES]; + bool all_cpus_has_been_started; + do { + all_cpus_has_been_started = true; + for (int cpu = 0; cpu < CONFIG_FREERTOS_NUMBER_OF_CORES; cpu++) { + all_cpus_has_been_started &= port_uxCoreStartupDone[cpu] != 0; + } + } while (!all_cpus_has_been_started); +#endif // !CONFIG_FREERTOS_UNICORE } -#endif -static void main_task(void* args) +// Reinitialize the startup stack heaps, so it can be used for heap allocation. +static void reclaim_startup_stack_memory_for_heap(void) { - ESP_LOGI(MAIN_TAG, "Started on CPU%d", (int)xPortGetCoreID()); -#if !CONFIG_FREERTOS_UNICORE - // Wait for FreeRTOS initialization to finish on other core, before replacing its startup stack - esp_register_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); - while (!s_other_cpu_startup_done) { - ; - } - esp_deregister_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); -#endif - + wait_for_all_cores_ready(); // [refactor-todo] check if there is a way to move the following block to esp_system startup heap_caps_enable_nonos_stack_heaps(); @@ -171,6 +171,13 @@ static void main_task(void* args) } } #endif +} + +static void main_task(void* args) +{ + ESP_LOGI(MAIN_TAG, "Started on CPU%d", (int)xPortGetCoreID()); + + reclaim_startup_stack_memory_for_heap(); // Initialize TWDT if configured to do so #if CONFIG_ESP_TASK_WDT_INIT