Prechádzať zdrojové kódy

Merge branch 'refactor/freertos_startup_and_common_functions' into 'master'

FreeRTOS: Refactor app startup and port common functions

See merge request espressif/esp-idf!21240
Darian 3 rokov pred
rodič
commit
f7d6f83c41

+ 6 - 4
components/freertos/CMakeLists.txt

@@ -51,7 +51,9 @@ if(${target} STREQUAL "linux")
         "${kernel_dir}/portable/${arch}/utils/wait_for_event.c")
 else()
     list(APPEND srcs
+        "app_startup.c"
         "FreeRTOS-openocd.c"
+        "port_common.c"
         "${kernel_dir}/portable/${arch}/portasm.S")
 
     list(APPEND private_include_dirs
@@ -62,7 +64,6 @@ else()
         list(APPEND include_dirs "${kernel_dir}/portable/${arch}/include/freertos") # Xtensa headers via #include "xx.h"
     else()
         list(APPEND srcs
-            "${kernel_dir}/portable/port_common.c"
             "${kernel_dir}/portable/port_systick.c"
             "esp_additions/freertos_v8_compat.c")
 
@@ -130,13 +131,14 @@ else()
         # FreeRTOS headers have a dependency on app_trace when SystemView tracing is enabled
         idf_component_optional_requires(PUBLIC app_trace)
     elseif(CONFIG_APPTRACE_ENABLE)
-        # [refactor-todo]: port.c has a dependency on esp_apptrace_init, for running it on APP CPU.
-        # this should be resolved when link-time registration of startup functions is added.
+        # [refactor-todo]: app_startup.c esp_startup_start_app_other_cores() has a dependency on esp_apptrace_init()
+        # (called on CPU1). This should be resolved when link-time registration of startup functions is added.
         idf_component_optional_requires(PRIVATE app_trace)
     endif()
 
     if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME)
-        # [refactor-todo]: port.c esp_startup_start_app_common() calls esp_gdbstub_init()
+        # [refactor-todo]: app_startup.c esp_startup_start_app_other_cores() calls esp_gdbstub_init() (called on CPU0).
+        # This should be resolved when link-time registration of startup functions is added.
         idf_component_optional_requires(PRIVATE esp_gdbstub)
     endif()
 

+ 1 - 150
components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c

@@ -35,24 +35,17 @@
 #include "hal/systimer_hal.h"
 #include "hal/systimer_ll.h"
 #endif
-
 #ifdef CONFIG_PM_TRACE
 #include "esp_private/pm_trace.h"
 #endif //CONFIG_PM_TRACE
 
-#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-#include "esp_gdbstub.h"
-#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-
 _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16");
 
 /* ---------------------------------------------------- Variables ------------------------------------------------------
  *
  * ------------------------------------------------------------------------------------------------------------------ */
 
-static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
-
-BaseType_t uxSchedulerRunning = 0;
+BaseType_t uxSchedulerRunning = 0;  // Duplicate of xSchedulerRunning, accessible to port files
 volatile UBaseType_t uxInterruptNesting = 0;
 portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
 portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
@@ -226,83 +219,7 @@ IRAM_ATTR void SysTickIsrHandler(void *arg)
 
 #endif // CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
 
-// --------------------- App Start-up ----------------------
-
-extern void app_main(void);
-
-static void main_task(void *args)
-{
-#if !CONFIG_FREERTOS_UNICORE
-    // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
-    while (uxSchedulerRunning == 0) {
-        ;
-    }
-#endif
-
-    // [refactor-todo] check if there is a way to move the following block to esp_system startup
-    heap_caps_enable_nonos_stack_heaps();
-
-    // Now we have startup stack RAM available for heap, enable any DMA pool memory
-#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
-    if (g_spiram_ok) {
-        esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
-        if (r != ESP_OK) {
-            ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
-            abort();
-        }
-    }
-#endif
-
-    //Initialize task wdt if configured to do so
-#if CONFIG_ESP_TASK_WDT_INIT
-    esp_task_wdt_config_t twdt_config = {
-        .timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
-        .idle_core_mask = 0,
-#if CONFIG_ESP_TASK_WDT_PANIC
-        .trigger_panic = true,
-#endif
-    };
-#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
-    twdt_config.idle_core_mask |= (1 << 0);
-#endif
-#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    twdt_config.idle_core_mask |= (1 << 1);
-#endif
-    ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
-#endif // CONFIG_ESP_TASK_WDT_INIT
 
-    app_main();
-    vTaskDelete(NULL);
-}
-
-void esp_startup_start_app_common(void)
-{
-#if CONFIG_ESP_INT_WDT_INIT
-    esp_int_wdt_init();
-    //Initialize the interrupt watch dog for CPU0.
-    esp_int_wdt_cpu_init();
-#endif
-
-    esp_crosscore_int_init();
-
-#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-    esp_gdbstub_init();
-#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-
-    portBASE_TYPE res = xTaskCreatePinnedToCore(main_task, "main",
-                                                ESP_TASK_MAIN_STACK, NULL,
-                                                ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
-    assert(res == pdTRUE);
-    (void)res;
-}
-
-void esp_startup_start_app(void)
-{
-    esp_startup_start_app_common();
-
-    ESP_LOGI(TAG, "Starting scheduler.");
-    vTaskStartScheduler();
-}
 
 /* ---------------------------------------------- Port Implementations -------------------------------------------------
  * Implementations of Porting Interface functions
@@ -468,72 +385,6 @@ void vPortFreeStack( void *pv )
 }
 #endif
 
-#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
-void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
-                                   StackType_t **ppxIdleTaskStackBuffer,
-                                   uint32_t *pulIdleTaskStackSize )
-{
-    StackType_t *pxStackBufferTemp;
-    StaticTask_t *pxTCBBufferTemp;
-
-    /* If the stack grows down then allocate the stack then the TCB so the stack
-     * does not grow into the TCB.  Likewise if the stack grows up then allocate
-     * the TCB then the stack. */
-    #if (portSTACK_GROWTH > 0)
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-        pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
-    }
-    #else /* portSTACK_GROWTH */
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-    }
-    #endif /* portSTACK_GROWTH */
-
-    assert(pxStackBufferTemp != NULL);
-    assert(pxTCBBufferTemp != NULL);
-    // Write back pointers
-    *ppxIdleTaskStackBuffer = pxStackBufferTemp;
-    *ppxIdleTaskTCBBuffer = pxTCBBufferTemp;
-    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
-}
-
-void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
-                                    StackType_t **ppxTimerTaskStackBuffer,
-                                    uint32_t *pulTimerTaskStackSize )
-{
-    StaticTask_t *pxTCBBufferTemp;
-    StackType_t *pxStackBufferTemp;
-
-    /* If the stack grows down then allocate the stack then the TCB so the stack
-     * does not grow into the TCB.  Likewise if the stack grows up then allocate
-     * the TCB then the stack. */
-    #if (portSTACK_GROWTH > 0)
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-        pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
-    }
-    #else /* portSTACK_GROWTH */
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-    }
-    #endif /* portSTACK_GROWTH */
-
-    assert(pxTCBBufferTemp != NULL);
-    assert(pxStackBufferTemp != NULL);
-    //Write back pointers
-    *ppxTimerTaskTCBBuffer = pxTCBBufferTemp;
-    *ppxTimerTaskStackBuffer = pxStackBufferTemp;
-    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
-}
-#endif //( configSUPPORT_STATIC_ALLOCATION == 1 )
-
 // ------------------------ Stack --------------------------
 
 /**

+ 1 - 194
components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c

@@ -32,18 +32,6 @@
 #include "esp_freertos_hooks.h"
 #include "esp_intr_alloc.h"
 #include "esp_memory_utils.h"
-#include "esp_chip_info.h"
-#if CONFIG_SPIRAM
-/* Required by esp_psram_extram_reserve_dma_pool() */
-#include "esp_psram.h"
-#include "esp_private/esp_psram_extram.h"
-#endif
-#ifdef CONFIG_APPTRACE_ENABLE
-#include "esp_app_trace.h"
-#endif
-#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-#include "esp_gdbstub.h"                    /* Required by esp_gdbstub_init() */
-#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
 #ifdef CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
 #include "soc/periph_defs.h"
 #include "soc/system_reg.h"
@@ -56,7 +44,7 @@ _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16")
 /*
 OS state variables
 */
-volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0};
+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
 //FreeRTOS SMP Locks
 portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
@@ -305,121 +293,6 @@ IRAM_ATTR void SysTickIsrHandler(void *arg)
 
 #endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 
-// --------------------- App Start-up ----------------------
-
-static const char *TAG = "cpu_start";
-
-extern void app_main(void);
-
-static void main_task(void *args)
-{
-#if !CONFIG_FREERTOS_UNICORE
-    // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
-    while (port_xSchedulerRunning[1] == 0) {
-        ;
-    }
-#endif
-
-    // [refactor-todo] check if there is a way to move the following block to esp_system startup
-    heap_caps_enable_nonos_stack_heaps();
-
-    // Now we have startup stack RAM available for heap, enable any DMA pool memory
-#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
-    if (esp_psram_is_initialized()) {
-        esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
-        if (r != ESP_OK) {
-            ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
-            abort();
-        }
-    }
-#endif
-
-    //Initialize TWDT if configured to do so
-#if CONFIG_ESP_TASK_WDT_INIT
-    esp_task_wdt_config_t twdt_config = {
-        .timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
-        .idle_core_mask = 0,
-#if CONFIG_ESP_TASK_WDT_PANIC
-        .trigger_panic = true,
-#endif
-    };
-#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
-    twdt_config.idle_core_mask |= (1 << 0);
-#endif
-#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    twdt_config.idle_core_mask |= (1 << 1);
-#endif
-    ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
-#endif // CONFIG_ESP_TASK_WDT
-
-    app_main();
-    vTaskDelete(NULL);
-}
-
-void esp_startup_start_app_common(void)
-{
-#if CONFIG_ESP_INT_WDT
-    esp_int_wdt_init();
-    //Initialize the interrupt watch dog for CPU0.
-    esp_int_wdt_cpu_init();
-#endif
-
-    esp_crosscore_int_init();
-
-#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-    esp_gdbstub_init();
-#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-
-    portBASE_TYPE res = xTaskCreatePinnedToCore(main_task, "main",
-                                                ESP_TASK_MAIN_STACK, NULL,
-                                                ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
-    assert(res == pdTRUE);
-    (void)res;
-}
-
-void esp_startup_start_app_other_cores(void)
-{
-    // For now, we only support up to two core: 0 and 1.
-    if (xPortGetCoreID() >= 2) {
-        abort();
-    }
-
-    // Wait for FreeRTOS initialization to finish on PRO CPU
-    while (port_xSchedulerRunning[0] == 0) {
-        ;
-    }
-
-#if CONFIG_APPTRACE_ENABLE
-    // [refactor-todo] move to esp_system initialization
-    esp_err_t err = esp_apptrace_init();
-    assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!");
-#endif
-
-#if CONFIG_ESP_INT_WDT
-    //Initialize the interrupt watch dog for CPU1.
-    esp_int_wdt_cpu_init();
-#endif
-
-    esp_crosscore_int_init();
-
-    ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
-    xPortStartScheduler();
-    abort(); /* Only get to here if FreeRTOS somehow very broken */
-}
-
-void esp_startup_start_app(void)
-{
-#if !CONFIG_ESP_INT_WDT
-#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
-    assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
-#endif
-#endif
-
-    esp_startup_start_app_common();
-
-    ESP_EARLY_LOGI(TAG, "Starting scheduler on PRO CPU.");
-    vTaskStartScheduler();
-}
 
 
 /* ---------------------------------------------- Port Implementations -------------------------------------------------
@@ -533,72 +406,6 @@ void vPortFreeStack( void *pv )
 }
 #endif
 
-#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
-void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
-                                   StackType_t **ppxIdleTaskStackBuffer,
-                                   uint32_t *pulIdleTaskStackSize )
-{
-    StackType_t *pxStackBufferTemp;
-    StaticTask_t *pxTCBBufferTemp;
-
-    /* If the stack grows down then allocate the stack then the TCB so the stack
-     * does not grow into the TCB.  Likewise if the stack grows up then allocate
-     * the TCB then the stack. */
-    #if (portSTACK_GROWTH > 0)
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-        pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
-    }
-    #else /* portSTACK_GROWTH */
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-    }
-    #endif /* portSTACK_GROWTH */
-
-    assert(pxStackBufferTemp != NULL);
-    assert(pxTCBBufferTemp != NULL);
-    // Write back pointers
-    *ppxIdleTaskStackBuffer = pxStackBufferTemp;
-    *ppxIdleTaskTCBBuffer = pxTCBBufferTemp;
-    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
-}
-
-void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
-                                    StackType_t **ppxTimerTaskStackBuffer,
-                                    uint32_t *pulTimerTaskStackSize )
-{
-    StaticTask_t *pxTCBBufferTemp;
-    StackType_t *pxStackBufferTemp;
-
-    /* If the stack grows down then allocate the stack then the TCB so the stack
-     * does not grow into the TCB.  Likewise if the stack grows up then allocate
-     * the TCB then the stack. */
-    #if (portSTACK_GROWTH > 0)
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-        pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
-    }
-    #else /* portSTACK_GROWTH */
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
-        pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
-    }
-    #endif /* portSTACK_GROWTH */
-
-    assert(pxTCBBufferTemp != NULL);
-    assert(pxStackBufferTemp != NULL);
-    //Write back pointers
-    *ppxTimerTaskTCBBuffer = pxTCBBufferTemp;
-    *ppxTimerTaskStackBuffer = pxStackBufferTemp;
-    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
-}
-#endif //( configSUPPORT_STATIC_ALLOCATION == 1 )
-
 // ------------------------ Stack --------------------------
 
 // User exception dispatcher when exiting

+ 4 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/port_idf.c

@@ -95,6 +95,7 @@ void vApplicationTickHook( void )
 
 void vPortYieldOtherCore( BaseType_t coreid ) { } // trying to skip for now
 
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
 /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
  * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
  * used by the Idle task. */
@@ -120,8 +121,10 @@ void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
      * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
     *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
 }
+#endif // configSUPPORT_STATIC_ALLOCATION == 1
 /*-----------------------------------------------------------*/
 
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
 /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
  * application must provide an implementation of vApplicationGetTimerTaskMemory()
  * to provide the memory that is used by the Timer service task. */
@@ -146,6 +149,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
      * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
     *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
 }
+#endif // configSUPPORT_STATIC_ALLOCATION == 1
 
 void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
 {

+ 0 - 230
components/freertos/FreeRTOS-Kernel/portable/port_common.c

@@ -1,230 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#include <string.h>
-#include "FreeRTOS.h"
-#include "task.h"
-#include "portmacro.h"
-#include "esp_private/esp_int_wdt.h"
-#include "esp_system.h"
-#include "esp_heap_caps_init.h"
-#include "esp_task_wdt.h"
-#include "esp_task.h"
-#include "esp_private/crosscore_int.h"
-#include "esp_log.h"
-#include "esp_memory_utils.h"
-#include "esp_freertos_hooks.h"
-#include "sdkconfig.h"
-#include "esp_freertos_hooks.h"
-
-#if CONFIG_SPIRAM
-#include "esp_psram.h"
-#include "esp_private/esp_psram_extram.h"
-#endif
-
-#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
-static const char* TAG = "cpu_start";
-#endif
-
-/* Architecture-agnostic parts of the FreeRTOS ESP-IDF port layer can go here.
- *
- * The actual call flow will be to call esp_startup_start_app() in <ARCH>/port.c,
- * which will then call esp_startup_start_app_common()
- */
-
-// Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting
-volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0};
-
-// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes)
-// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
-// should mirror each other's values.
-//
-// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE.
-#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
-    #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores."
-#endif
-
-static void main_task(void* args);
-
-#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-void esp_gdbstub_init(void);
-#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-
-extern void app_main(void);
-
-void esp_startup_start_app_common(void)
-{
-#if CONFIG_ESP_INT_WDT
-    esp_int_wdt_init();
-    //Initialize the interrupt watch dog for CPU0.
-    esp_int_wdt_cpu_init();
-#endif
-
-    esp_crosscore_int_init();
-
-#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME && !CONFIG_IDF_TARGET_ESP32C2
-    esp_gdbstub_init();
-#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
-
-    portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
-                                                ESP_TASK_MAIN_STACK, NULL,
-                                                ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
-    assert(res == pdTRUE);
-    (void)res;
-}
-
-#if !CONFIG_FREERTOS_UNICORE
-static volatile bool s_other_cpu_startup_done = false;
-static bool other_cpu_startup_idle_hook_cb(void)
-{
-    s_other_cpu_startup_done = true;
-    return true;
-}
-#endif
-
-static void main_task(void* args)
-{
-#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
-
-    // [refactor-todo] check if there is a way to move the following block to esp_system startup
-    heap_caps_enable_nonos_stack_heaps();
-
-    // Now we have startup stack RAM available for heap, enable any DMA pool memory
-#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
-    if (esp_psram_is_initialized()) {
-        esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
-        if (r != ESP_OK) {
-            ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
-            abort();
-        }
-    }
-#endif
-
-    //Initialize TWDT if configured to do so
-#if CONFIG_ESP_TASK_WDT_INIT
-    esp_task_wdt_config_t twdt_config = {
-        .timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
-        .idle_core_mask = 0,
-#if CONFIG_ESP_TASK_WDT_PANIC
-        .trigger_panic = true,
-#endif
-    };
-#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
-    twdt_config.idle_core_mask |= (1 << 0);
-#endif
-#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    twdt_config.idle_core_mask |= (1 << 1);
-#endif
-    ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
-#endif // CONFIG_ESP_TASK_WDT
-
-    app_main();
-    vTaskDelete(NULL);
-}
-
-// -------------------- Heap Related -----------------------
-
-bool xPortCheckValidTCBMem(const void *ptr)
-{
-    return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
-}
-
-bool xPortcheckValidStackMem(const void *ptr)
-{
-#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
-    return esp_ptr_byte_accessible(ptr);
-#else
-    return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
-#endif
-}
-
-// ------------- FreeRTOS Static Allocation ----------------
-
-/*
-This function is required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is
-enabled and is used by FreeRTOS to obtain memory for its IDLE tasks.
-
-Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack
-memory MUST be placed in internal RAM.
-*/
-void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
-                                   StackType_t **ppxIdleTaskStackBuffer,
-                                   uint32_t *pulIdleTaskStackSize )
-{
-    StaticTask_t *pxTCBBufferTemp;
-    StackType_t *pxStackBufferTemp;
-
-    /* If the stack grows down then allocate the stack then the TCB so the stack
-     * does not grow into the TCB.  Likewise if the stack grows up then allocate
-     * the TCB then the stack. */
-    #if (portSTACK_GROWTH > 0)
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
-        pxStackBufferTemp = pvPortMallocStackMem(configMINIMAL_STACK_SIZE);
-    }
-    #else /* portSTACK_GROWTH */
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxStackBufferTemp = pvPortMallocStackMem(configMINIMAL_STACK_SIZE);
-        pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
-    }
-    #endif /* portSTACK_GROWTH */
-
-    assert(pxTCBBufferTemp != NULL);
-    assert(pxStackBufferTemp != NULL);
-    //Write back pointers
-    *ppxIdleTaskTCBBuffer = pxTCBBufferTemp;
-    *ppxIdleTaskStackBuffer = pxStackBufferTemp;
-    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
-}
-
-/*
-This function is required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is
-enabled and is used by the FreeRTOS Timer to obtain memory for its daemone task.
-
-
-Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack
-memory MUST be placed in internal RAM.
-*/
-void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
-                                    StackType_t **ppxTimerTaskStackBuffer,
-                                    uint32_t *pulTimerTaskStackSize )
-{
-    StaticTask_t *pxTCBBufferTemp;
-    StackType_t *pxStackBufferTemp;
-
-    /* If the stack grows down then allocate the stack then the TCB so the stack
-     * does not grow into the TCB.  Likewise if the stack grows up then allocate
-     * the TCB then the stack. */
-    #if (portSTACK_GROWTH > 0)
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
-        pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
-    }
-    #else /* portSTACK_GROWTH */
-    {
-        //Allocate TCB and stack buffer in internal memory
-        pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
-        pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
-    }
-    #endif /* portSTACK_GROWTH */
-
-    assert(pxTCBBufferTemp != NULL);
-    assert(pxStackBufferTemp != NULL);
-    //Write back pointers
-    *ppxTimerTaskTCBBuffer = pxTCBBufferTemp;
-    *ppxTimerTaskStackBuffer = pxStackBufferTemp;
-    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
-}

+ 1 - 16
components/freertos/FreeRTOS-Kernel/portable/riscv/port.c

@@ -63,8 +63,6 @@ _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16")
  *
  * ------------------------------------------------------------------------------------------------------------------ */
 
-static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
-
 /**
  * @brief A variable is used to keep track of the critical section nesting.
  * @note This variable has to be stored as part of the task context and must be initialized to a non zero value
@@ -73,7 +71,7 @@ static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate t
  */
 static UBaseType_t uxCriticalNesting = 0;
 static UBaseType_t uxSavedInterruptState = 0;
-BaseType_t uxSchedulerRunning = 0;
+BaseType_t uxSchedulerRunning = 0;  // Duplicate of xSchedulerRunning, accessible to port files
 UBaseType_t uxInterruptNesting = 0;
 BaseType_t xPortSwitchFlag = 0;
 __attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
@@ -473,16 +471,3 @@ void vPortSetStackWatchpoint(void *pxStackStart)
 /* ---------------------------------------------- Misc Implementations -------------------------------------------------
  *
  * ------------------------------------------------------------------------------------------------------------------ */
-
-// --------------------- App Start-up ----------------------
-
-/* [refactor-todo]: See if we can include this through a header */
-extern void esp_startup_start_app_common(void);
-
-void esp_startup_start_app(void)
-{
-    esp_startup_start_app_common();
-
-    ESP_LOGI(TAG, "Starting scheduler.");
-    vTaskStartScheduler();
-}

+ 1 - 56
components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c

@@ -69,15 +69,11 @@
 #include "esp_private/esp_int_wdt.h"
 #include "esp_system.h"
 #include "esp_log.h"
-#ifdef CONFIG_APPTRACE_ENABLE
-#include "esp_app_trace.h"    /* Required for esp_apptrace_init. [refactor-todo] */
-#endif
 #include "FreeRTOS.h"        /* This pulls in portmacro.h */
 #include "task.h"            /* Required for TaskHandle_t, tskNO_AFFINITY, and vTaskStartScheduler */
 #include "port_systick.h"
 #include "esp_cpu.h"
 #include "esp_memory_utils.h"
-#include "esp_chip_info.h"
 
 _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16");
 
@@ -88,8 +84,7 @@ _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_A
  *
  * ------------------------------------------------------------------------------------------------------------------ */
 
-static const char *TAG = "cpu_start"; /* [refactor-todo]: might be appropriate to change in the future, but for now maintain the same log output */
-extern volatile int port_xSchedulerRunning[portNUM_PROCESSORS];
+volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates whether scheduler is running on a per-core basis
 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};
@@ -618,53 +613,3 @@ void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings )
     _xt_coproc_release( xMPUSettings->coproc_area );
 }
 #endif /* portUSING_MPU_WRAPPERS */
-
-// --------------------- App Start-up ----------------------
-
-#if !CONFIG_FREERTOS_UNICORE
-void esp_startup_start_app_other_cores(void)
-{
-    // For now, we only support up to two core: 0 and 1.
-    if (xPortGetCoreID() >= 2) {
-        abort();
-    }
-
-    // Wait for FreeRTOS initialization to finish on PRO CPU
-    while (port_xSchedulerRunning[0] == 0) {
-        ;
-    }
-
-#if CONFIG_APPTRACE_ENABLE
-    // [refactor-todo] move to esp_system initialization
-    esp_err_t err = esp_apptrace_init();
-    assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!");
-#endif
-
-#if CONFIG_ESP_INT_WDT
-    //Initialize the interrupt watch dog for CPU1.
-    esp_int_wdt_cpu_init();
-#endif
-
-    esp_crosscore_int_init();
-
-    ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
-    xPortStartScheduler();
-    abort(); /* Only get to here if FreeRTOS somehow very broken */
-}
-#endif // !CONFIG_FREERTOS_UNICORE
-
-extern void esp_startup_start_app_common(void);
-
-void esp_startup_start_app(void)
-{
-#if !CONFIG_ESP_INT_WDT
-#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
-    assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
-#endif
-#endif
-
-    esp_startup_start_app_common();
-
-    ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
-    vTaskStartScheduler();
-}

+ 207 - 0
components/freertos/app_startup.c

@@ -0,0 +1,207 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "sdkconfig.h"
+#include <stddef.h>
+#include <assert.h>
+#include "esp_task.h"
+#include "esp_log.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/portmacro.h"
+#include "esp_private/esp_int_wdt.h"
+#include "esp_private/crosscore_int.h"
+#include "esp_task_wdt.h"
+#include "esp_freertos_hooks.h"
+#include "esp_heap_caps_init.h"
+#include "esp_chip_info.h"
+#if CONFIG_SPIRAM
+/* Required by esp_psram_extram_reserve_dma_pool() */
+#include "esp_psram.h"
+#include "esp_private/esp_psram_extram.h"
+#endif
+#ifdef CONFIG_APPTRACE_ENABLE
+#include "esp_app_trace.h"    /* Required for esp_apptrace_init. [refactor-todo] */
+#endif
+#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
+#include "esp_gdbstub.h"                    /* Required by esp_gdbstub_init() */
+#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
+
+/* ------------------------------------------------- App/OS Startup ----------------------------------------------------
+ * - Functions related to application and FreeRTOS startup
+ * - This startup is common to all architectures (e.g. RISC-V and Xtensa) and all FreeRTOS implementations (i.e., IDF
+ *   FreeRTOS and Amazon SMP FreeRTOS).
+ * - Application startup flow as follows:
+ *      - For CPU 0
+ *          - CPU0 completes CPU startup (in startup.c), then calls esp_startup_start_app()
+ *          - esp_startup_start_app() registers some daemon services for CPU0 then starts FreeRTOS
+ *      - For CPUx (1 to N-1)
+ *          - CPUx completes CPU startup in startup.c, then calls esp_startup_start_app_other_cores()
+ *          - esp_startup_start_app_other_cores(), registers some daemon services for CPUx, waits for CPU0 to start
+ *            FreeRTOS, then yields (via xPortStartScheduler()) to schedule a task.
+ * ------------------------------------------------------------------------------------------------------------------ */
+
+// ----------------------- Checks --------------------------
+
+/*
+For now, AMP is not supported (i.e., running FreeRTOS on one core and a bare metal/other OS on the other). Therefore,
+CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE should be identical. We add a check for this here.
+*/
+#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
+    #error "AMP not supported. FreeRTOS number of cores and system number of cores must be identical"
+#endif
+
+// -------------------- Declarations -----------------------
+
+static void main_task(void* args);
+static const char* APP_START_TAG = "app_start";
+
+// ------------------ CPU0 App Startup ---------------------
+
+void esp_startup_start_app(void)
+{
+#if CONFIG_ESP_INT_WDT
+    esp_int_wdt_init();
+    // Initialize the interrupt watch dog for CPU0.
+    esp_int_wdt_cpu_init();
+#elif CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
+    // If the INT WDT isn't enabled on ESP32 ECO3, issue an error regarding the cache lock bug
+    assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
+#endif
+
+    // Initialize the cross-core interrupt on CPU0
+    esp_crosscore_int_init();
+
+#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME && !CONFIG_IDF_TARGET_ESP32C2
+    void esp_gdbstub_init(void);
+    esp_gdbstub_init();
+#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
+
+    BaseType_t res = xTaskCreatePinnedToCore(main_task, "main",
+                                             ESP_TASK_MAIN_STACK, NULL,
+                                             ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
+    assert(res == pdTRUE);
+    (void)res;
+
+    /*
+    If a particular FreeRTOS port has port/arch specific OS startup behavior, they can implement a function of type
+    "void port_start_app_hook(void)" in their `port.c` files. This function will be called below, thus allowing each
+    FreeRTOS port to implement port specific app startup behavior.
+    */
+    void __attribute__((weak)) port_start_app_hook(void);
+    if (port_start_app_hook != NULL) {
+        port_start_app_hook();
+    }
+
+    ESP_EARLY_LOGI(APP_START_TAG, "Starting scheduler on CPU0");
+    vTaskStartScheduler();
+}
+
+// --------------- CPU[1:N-1] App Startup ------------------
+
+#if !CONFIG_FREERTOS_UNICORE
+void esp_startup_start_app_other_cores(void)
+{
+    // For now, we only support up to two core: 0 and 1.
+    if (xPortGetCoreID() >= 2) {
+        abort();
+    }
+
+    // Wait for CPU0 to start FreeRTOS before progressing
+    extern volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS];
+    while (port_xSchedulerRunning[0] == 0) {
+        ;
+    }
+
+#if CONFIG_APPTRACE_ENABLE
+    // [refactor-todo] move to esp_system initialization
+    esp_err_t err = esp_apptrace_init();
+    assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!");
+#endif
+
+#if CONFIG_ESP_INT_WDT
+    // Initialize the interrupt watch dog for CPU1.
+    esp_int_wdt_cpu_init();
+#endif
+
+    // Initialize the cross-core interrupt on CPU1
+    esp_crosscore_int_init();
+
+    ESP_EARLY_LOGI(APP_START_TAG, "Starting scheduler on CPU%d", xPortGetCoreID());
+    xPortStartScheduler();
+    abort(); // Only get to here if FreeRTOS somehow very broken
+}
+#endif // !CONFIG_FREERTOS_UNICORE
+
+/* ---------------------------------------------------- Main Task ------------------------------------------------------
+ * - main_task is a daemon task created by CPU0 before it starts FreeRTOS
+ *      - Pinned to CPU(ESP_TASK_MAIN_CORE)
+ *      - Priority of ESP_TASK_MAIN_PRIO
+ * - Used to dispatch "void app_main(void)" provided by the application
+ * - main_task will self delete if app_main returns
+ * ------------------------------------------------------------------------------------------------------------------ */
+
+static const char* 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)
+{
+    s_other_cpu_startup_done = true;
+    return true;
+}
+#endif
+
+static void main_task(void* args)
+{
+    ESP_LOGI(MAIN_TAG, "Started on CPU%d", 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
+
+    // [refactor-todo] check if there is a way to move the following block to esp_system startup
+    heap_caps_enable_nonos_stack_heaps();
+
+    // Now we have startup stack RAM available for heap, enable any DMA pool memory
+#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
+    if (esp_psram_is_initialized()) {
+        esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
+        if (r != ESP_OK) {
+            ESP_LOGE(MAIN_TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
+            abort();
+        }
+    }
+#endif
+
+    // Initialize TWDT if configured to do so
+#if CONFIG_ESP_TASK_WDT_INIT
+    esp_task_wdt_config_t twdt_config = {
+        .timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
+        .idle_core_mask = 0,
+#if CONFIG_ESP_TASK_WDT_PANIC
+        .trigger_panic = true,
+#endif
+    };
+#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
+    twdt_config.idle_core_mask |= (1 << 0);
+#endif
+#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
+    twdt_config.idle_core_mask |= (1 << 1);
+#endif
+    ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
+#endif // CONFIG_ESP_TASK_WDT
+
+    ESP_LOGI(MAIN_TAG, "Calling app_main()");
+    extern void app_main(void);
+    app_main();
+    ESP_LOGI(MAIN_TAG, "Returned from app_main()");
+    vTaskDelete(NULL);
+}

+ 6 - 8
components/freertos/linker.lf

@@ -130,14 +130,12 @@ entries:
             queue: uxQueueGetQueueNumber (default)
             queue: vQueueSetQueueNumber (default)
             queue: ucQueueGetQueueType (default)
-    # port.c Functions
-    port: esp_startup_start_app (default)
-    if ESP_SYSTEM_SINGLE_CORE_MODE = n:
-        port: esp_startup_start_app_other_cores (default)
+    # app_startup.c
+    app_startup: esp_startup_start_app (default)
+    if CONFIG_FREERTOS_UNICORE = n:
+        app_startup: esp_startup_start_app_other_cores (default)
+        app_startup: other_cpu_startup_idle_hook_cb (default)
+    app_startup: main_task (default)
     # port_common.c Functions
-    port_common:main_task (default)
-    port_common:esp_startup_start_app_common (default)
     port_common:vApplicationGetIdleTaskMemory (default)
     port_common:vApplicationGetTimerTaskMemory (default)
-    if FREERTOS_UNICORE = n:
-        port_common:other_cpu_startup_idle_hook_cb (default)

+ 6 - 4
components/freertos/linker_smp.lf

@@ -144,10 +144,12 @@ entries:
         # port
         port: pxPortInitialiseStack (default)
         port: xPortStartScheduler (default)
-        port: main_task (default)
-        port: esp_startup_start_app (default)
-        if ESP_SYSTEM_SINGLE_CORE_MODE = n:
-            port:esp_startup_start_app_other_cores (default)
+        # app_startup.c
+        app_startup: esp_startup_start_app (default)
+        if CONFIG_FREERTOS_UNICORE = n:
+            app_startup: esp_startup_start_app_other_cores (default)
+            app_startup: other_cpu_startup_idle_hook_cb (default)
+        app_startup: main_task (default)
         # timers.c
         timers: xTimerCreateTimerTask (default)
         timers: xTimerCreate (default)

+ 130 - 0
components/freertos/port_common.c

@@ -0,0 +1,130 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "esp_system.h"
+#include "esp_memory_utils.h"
+#include "sdkconfig.h"
+
+/* ----------------------------------------- Port Implementations (Common)  --------------------------------------------
+ * - Common FreeRTOS port function implementations
+ * - These functions are common to all FreeRTOS ports (i.e., on all architectures and all FreeRTOS implementations).
+ * ------------------------------------------------------------------------------------------------------------------ */
+
+// -------------------- Heap Related -----------------------
+
+#if !CONFIG_FREERTOS_SMP    // IDF-3997
+bool xPortCheckValidTCBMem(const void *ptr)
+{
+    return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
+}
+
+bool xPortcheckValidStackMem(const void *ptr)
+{
+#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
+    return esp_ptr_byte_accessible(ptr);
+#else
+    return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
+#endif
+}
+#endif
+
+// ------------- FreeRTOS Static Allocation ----------------
+
+/*
+These function are required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is
+enabled and is used by FreeRTOS to obtain memory for its IDLE/Timer tasks.
+
+Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack
+memory MUST be placed in internal RAM.
+*/
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
+                                   StackType_t **ppxIdleTaskStackBuffer,
+                                   uint32_t *pulIdleTaskStackSize )
+{
+    StaticTask_t *pxTCBBufferTemp;
+    StackType_t *pxStackBufferTemp;
+
+    /* If the stack grows down then allocate the stack then the TCB so the stack
+     * does not grow into the TCB.  Likewise if the stack grows up then allocate
+     * the TCB then the stack. */
+    #if (portSTACK_GROWTH > 0)
+    {
+        //Allocate TCB and stack buffer in internal memory
+        #if CONFIG_FREERTOS_SMP     // IDF-3997
+            pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
+            pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
+        #else
+            pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
+            pxStackBufferTemp = pvPortMallocStackMem(configMINIMAL_STACK_SIZE);
+        #endif /* CONFIG_FREERTOS_SMP */
+    }
+    #else /* portSTACK_GROWTH */
+    {
+        //Allocate TCB and stack buffer in internal memory
+        #if CONFIG_FREERTOS_SMP     // IDF-3997
+            pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
+            pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
+        #else
+            pxStackBufferTemp = pvPortMallocStackMem(configMINIMAL_STACK_SIZE);
+            pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
+        #endif /* CONFIG_FREERTOS_SMP */
+    }
+    #endif /* portSTACK_GROWTH */
+
+    assert(pxTCBBufferTemp != NULL);
+    assert(pxStackBufferTemp != NULL);
+    //Write back pointers
+    *ppxIdleTaskTCBBuffer = pxTCBBufferTemp;
+    *ppxIdleTaskStackBuffer = pxStackBufferTemp;
+    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
+}
+
+void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
+                                    StackType_t **ppxTimerTaskStackBuffer,
+                                    uint32_t *pulTimerTaskStackSize )
+{
+    StaticTask_t *pxTCBBufferTemp;
+    StackType_t *pxStackBufferTemp;
+
+    /* If the stack grows down then allocate the stack then the TCB so the stack
+     * does not grow into the TCB.  Likewise if the stack grows up then allocate
+     * the TCB then the stack. */
+    #if (portSTACK_GROWTH > 0)
+    {
+        //Allocate TCB and stack buffer in internal memory
+        #if CONFIG_FREERTOS_SMP     // IDF-3997
+            pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
+            pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
+        #else
+            pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
+            pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
+        #endif /* CONFIG_FREERTOS_SMP */
+    }
+    #else /* portSTACK_GROWTH */
+    {
+        //Allocate TCB and stack buffer in internal memory
+        #if CONFIG_FREERTOS_SMP     // IDF-3997
+            pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
+            pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
+        #else
+            pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
+            pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
+        #endif /* CONFIG_FREERTOS_SMP */
+    }
+    #endif /* portSTACK_GROWTH */
+
+    assert(pxTCBBufferTemp != NULL);
+    assert(pxStackBufferTemp != NULL);
+    //Write back pointers
+    *ppxTimerTaskTCBBuffer = pxTCBBufferTemp;
+    *ppxTimerTaskStackBuffer = pxStackBufferTemp;
+    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
+}
+#endif // configSUPPORT_STATIC_ALLOCATION == 1

+ 4 - 2
tools/unit-test-app/components/test_utils/test_runner.c

@@ -21,8 +21,10 @@
 
 static void unity_task(void *pvParameters)
 {
-    vTaskDelay(2); /* Delay a bit to let the main task be deleted */
-    unity_run_menu(); /* Doesn't return */
+    // Delay a bit to let the main task and any other startup tasks be deleted
+    vTaskDelay(pdMS_TO_TICKS(50));
+    // Start running unity (prints test menu and doesn't return)
+    unity_run_menu();
 }
 
 void test_main(void)