diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 16c7c4bc8..0275f9b3c 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -419,4 +419,15 @@ endif #FREERTOS_UNICORE endif # FREERTOS_DEBUG_INTERNALS +config FREERTOS_TASK_FUNCTION_WRAPPER + bool "Enclose all task functions in a wrapper function" + depends on OPTIMIZATION_LEVEL_DEBUG + default y + help + If enabled, all FreeRTOS task functions will be enclosed in a wrapper function. + If a task function mistakenly returns (i.e. does not delete), the call flow will + return to the wrapper function. The wrapper function will then log an error and + abort the application. This option is also required for GDB backtraces and C++ + exceptions to work correctly inside top-level task functions. + endmenu diff --git a/components/freertos/port.c b/components/freertos/port.c index 98fe13d36..3f6d11d11 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -108,6 +108,7 @@ #include "esp_crosscore_int.h" #include "esp_intr_alloc.h" +#include "esp_log.h" /* Defined in portasm.h */ extern void _frxt_tick_timer_init(void); @@ -133,6 +134,18 @@ unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting // User exception dispatcher when exiting void _xt_user_exit(void); +#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER +// Wrapper to allow task functions to return (increases stack overhead by 16 bytes) +static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters) +{ + pxCode(pvParameters); + //FreeRTOS tasks should not return. Log the task name and abort. + char * pcTaskName = pcTaskGetTaskName(NULL); + ESP_LOGE("FreeRTOS", "FreeRTOS Task \"%s\" should not return, Aborting now!", pcTaskName); + abort(); +} +#endif + /* * Stack initialization */ @@ -173,19 +186,33 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px frame = (XtExcFrame *) sp; /* Explicitly initialize certain saved registers */ - frame->pc = (UBaseType_t) pxCode; /* task entrypoint */ - frame->a0 = 0; /* to terminate GDB backtrace */ - frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */ - frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */ + #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER + frame->pc = (UBaseType_t) vPortTaskWrapper; /* task wrapper */ + #else + frame->pc = (UBaseType_t) pxCode; /* task entrypoint */ + #endif + frame->a0 = 0; /* to terminate GDB backtrace */ + frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */ + frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ /* Also set entry point argument parameter. */ #ifdef __XTENSA_CALL0_ABI__ - frame->a2 = (UBaseType_t) pvParameters; + #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER + frame->a2 = (UBaseType_t) pxCode; + frame->a3 = (UBaseType_t) pvParameters; + #else + frame->a2 = (UBaseType_t) pvParameters; + #endif frame->ps = PS_UM | PS_EXCM; #else /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ - frame->a6 = (UBaseType_t) pvParameters; + #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER + frame->a6 = (UBaseType_t) pxCode; + frame->a7 = (UBaseType_t) pvParameters; + #else + frame->a6 = (UBaseType_t) pvParameters; + #endif frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1); #endif diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index c2f72f5f6..b334bb9db 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -496,3 +496,11 @@ functionality of :cpp:func:`xTaskCreateStaticPinnedToCore` in ESP-IDF FreeRTOS particular functions in ESP-IDF FreeRTOS which have not been fully tested in an SMP context. +:envvar:`CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER` will enclose all task functions +within a wrapper function. In the case that a task function mistakenly returns +(i.e. does not call :cpp:func:`vTaskDelete`), the call flow will return to the +wrapper function. The wrapper function will then log an error and abort the +application, as illustrated below:: + + E (25) FreeRTOS: FreeRTOS task should not return. Aborting now! + abort() was called at PC 0x40085c53 on core 0