mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 10:47:19 +02:00
Merge branch 'staging/riscv_wrapper_freertos_tasks_v5.0' into 'release/v5.0'
RISC-V: Create a wrapper around FreeRTOS Tasks to detect the ones returning (backport v5.0) See merge request espressif/esp-idf!21202
This commit is contained in:
@ -247,8 +247,8 @@ void esp_panic_handler(panic_info_t *info)
|
|||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------------------
|
||||||
* core - core where exception was triggered
|
* core - core where exception was triggered
|
||||||
* exception - what kind of exception occured
|
* exception - what kind of exception occurred
|
||||||
* description - a short description regarding the exception that occured
|
* description - a short description regarding the exception that occurred
|
||||||
* details - more details about the exception
|
* details - more details about the exception
|
||||||
* state - processor state like register contents, and backtrace
|
* state - processor state like register contents, and backtrace
|
||||||
* elf_info - details about the image currently running
|
* elf_info - details about the image currently running
|
||||||
@ -313,6 +313,14 @@ void esp_panic_handler(panic_info_t *info)
|
|||||||
PANIC_INFO_DUMP(info, state);
|
PANIC_INFO_DUMP(info, state);
|
||||||
panic_print_str("\r\n");
|
panic_print_str("\r\n");
|
||||||
|
|
||||||
|
/* No matter if we come here from abort or an exception, this variable must be reset.
|
||||||
|
* Else, any exception/error occurring during the current panic handler would considered
|
||||||
|
* an abort. Do this after PANIC_INFO_DUMP(info, state) as it also checks this variable.
|
||||||
|
* For example, if coredump triggers a stack overflow and this variable is not reset,
|
||||||
|
* the second panic would be still be marked as the result of an abort, even the previous
|
||||||
|
* message reason would be kept. */
|
||||||
|
g_panic_abort = false;
|
||||||
|
|
||||||
#ifdef WITH_ELF_SHA256
|
#ifdef WITH_ELF_SHA256
|
||||||
panic_print_str("\r\nELF file SHA256: ");
|
panic_print_str("\r\nELF file SHA256: ");
|
||||||
char sha256_buf[65];
|
char sha256_buf[65];
|
||||||
@ -349,10 +357,6 @@ void esp_panic_handler(panic_info_t *info)
|
|||||||
} else {
|
} else {
|
||||||
disable_all_wdts();
|
disable_all_wdts();
|
||||||
s_dumping_core = true;
|
s_dumping_core = true;
|
||||||
/* No matter if we come here from abort or an exception, this variable must be reset.
|
|
||||||
* Else, any exception/error occuring during the current panic handler would considered
|
|
||||||
* an abort. */
|
|
||||||
g_panic_abort = false;
|
|
||||||
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
|
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
|
||||||
esp_core_dump_to_flash(info);
|
esp_core_dump_to_flash(info);
|
||||||
#endif
|
#endif
|
||||||
|
@ -515,30 +515,29 @@ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
|
|||||||
#endif //( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#endif //( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
// ------------------------ Stack --------------------------
|
// ------------------------ Stack --------------------------
|
||||||
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
__attribute__((noreturn)) static void _prvTaskExitError(void)
|
/**
|
||||||
|
* Wrapper to allow task functions to return. Force the optimization option -O1 on that function to make sure there
|
||||||
|
* is no tail-call. Indeed, we need the compiler to keep the return address to this function when calling `panic_abort`.
|
||||||
|
*
|
||||||
|
* Thanks to `naked` attribute, the compiler won't generate a prologue and epilogue for the function, which saves time
|
||||||
|
* and stack space.
|
||||||
|
*/
|
||||||
|
static void __attribute__((optimize("O1"), naked)) vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
|
||||||
{
|
{
|
||||||
/* A function that implements a task must not exit or attempt to return to
|
asm volatile(".cfi_undefined ra\n");
|
||||||
its caller as there is nothing to return to. If a task wants to exit it
|
extern void __attribute__((noreturn)) panic_abort(const char *details);
|
||||||
should instead call vTaskDelete( NULL ).
|
static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0";
|
||||||
|
pxCode(pvParameters);
|
||||||
Artificially force an assert() to be triggered if configASSERT() is
|
//FreeRTOS tasks should not return. Log the task name and abort.
|
||||||
defined, then stop here so application writers can catch the error. */
|
char *pcTaskName = pcTaskGetName(NULL);
|
||||||
portDISABLE_INTERRUPTS();
|
/* We cannot use s(n)printf because it is in flash */
|
||||||
abort();
|
strcat(msg, pcTaskName);
|
||||||
|
strcat(msg, "\" should not return, Aborting now!");
|
||||||
|
panic_abort(msg);
|
||||||
}
|
}
|
||||||
|
#endif // CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
|
|
||||||
__attribute__((naked)) static void prvTaskExitError(void)
|
|
||||||
{
|
|
||||||
asm volatile(".option push\n" \
|
|
||||||
".option norvc\n" \
|
|
||||||
"nop\n" \
|
|
||||||
".option pop");
|
|
||||||
/* Task entry's RA will point here. Shifting RA into prvTaskExitError is necessary
|
|
||||||
to make GDB backtrace ending inside that function.
|
|
||||||
Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */
|
|
||||||
_prvTaskExitError();
|
|
||||||
}
|
|
||||||
|
|
||||||
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
||||||
{
|
{
|
||||||
@ -602,11 +601,16 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
|||||||
sp -= RV_STK_FRMSZ;
|
sp -= RV_STK_FRMSZ;
|
||||||
RvExcFrame *frame = (RvExcFrame *)sp;
|
RvExcFrame *frame = (RvExcFrame *)sp;
|
||||||
memset(frame, 0, sizeof(*frame));
|
memset(frame, 0, sizeof(*frame));
|
||||||
/* Shifting RA into prvTaskExitError is necessary to make GDB backtrace ending inside that function.
|
|
||||||
Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */
|
/* Initialize the stack frame. */
|
||||||
frame->ra = (UBaseType_t)prvTaskExitError + 4/*size of the nop insruction at the beginning of prvTaskExitError*/;
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
frame->mepc = (UBaseType_t)pxCode;
|
frame->mepc = (UBaseType_t)vPortTaskWrapper;
|
||||||
frame->a0 = (UBaseType_t)pvParameters;
|
frame->a0 = (UBaseType_t)pxCode;
|
||||||
|
frame->a1 = (UBaseType_t)pvParameters;
|
||||||
|
#else
|
||||||
|
frame->mepc = (UBaseType_t)pxCode;
|
||||||
|
frame->a0 = (UBaseType_t)pvParameters;
|
||||||
|
#endif // CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
frame->gp = (UBaseType_t)&__global_pointer$;
|
frame->gp = (UBaseType_t)&__global_pointer$;
|
||||||
frame->tp = (UBaseType_t)threadptr;
|
frame->tp = (UBaseType_t)threadptr;
|
||||||
|
|
||||||
|
@ -113,31 +113,29 @@ void vPortEndScheduler(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------ Stack --------------------------
|
// ------------------------ Stack --------------------------
|
||||||
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
__attribute__((noreturn)) static void _prvTaskExitError(void)
|
/**
|
||||||
|
* Wrapper to allow task functions to return. Force the optimization option -O1 on that function to make sure there
|
||||||
|
* is no tail-call. Indeed, we need the compiler to keep the return address to this function when calling `panic_abort`.
|
||||||
|
*
|
||||||
|
* Thanks to `naked` attribute, the compiler won't generate a prologue and epilogue for the function, which saves time
|
||||||
|
* and stack space.
|
||||||
|
*/
|
||||||
|
static void __attribute__((optimize("O1"), naked)) vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
|
||||||
{
|
{
|
||||||
/* A function that implements a task must not exit or attempt to return to
|
asm volatile(".cfi_undefined ra\n");
|
||||||
its caller as there is nothing to return to. If a task wants to exit it
|
extern void __attribute__((noreturn)) panic_abort(const char *details);
|
||||||
should instead call vTaskDelete( NULL ).
|
static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0";
|
||||||
|
pxCode(pvParameters);
|
||||||
Artificially force an assert() to be triggered if configASSERT() is
|
//FreeRTOS tasks should not return. Log the task name and abort.
|
||||||
defined, then stop here so application writers can catch the error. */
|
char *pcTaskName = pcTaskGetName(NULL);
|
||||||
configASSERT(uxCriticalNesting == ~0UL);
|
/* We cannot use s(n)printf because it is in flash */
|
||||||
portDISABLE_INTERRUPTS();
|
strcat(msg, pcTaskName);
|
||||||
abort();
|
strcat(msg, "\" should not return, Aborting now!");
|
||||||
|
panic_abort(msg);
|
||||||
}
|
}
|
||||||
|
#endif // CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
|
|
||||||
__attribute__((naked)) static void prvTaskExitError(void)
|
|
||||||
{
|
|
||||||
asm volatile(".option push\n" \
|
|
||||||
".option norvc\n" \
|
|
||||||
"nop\n" \
|
|
||||||
".option pop");
|
|
||||||
/* Task entry's RA will point here. Shifting RA into prvTaskExitError is necessary
|
|
||||||
to make GDB backtrace ending inside that function.
|
|
||||||
Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */
|
|
||||||
_prvTaskExitError();
|
|
||||||
}
|
|
||||||
|
|
||||||
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
||||||
{
|
{
|
||||||
@ -201,12 +199,18 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
|||||||
sp -= RV_STK_FRMSZ;
|
sp -= RV_STK_FRMSZ;
|
||||||
RvExcFrame *frame = (RvExcFrame *)sp;
|
RvExcFrame *frame = (RvExcFrame *)sp;
|
||||||
memset(frame, 0, sizeof(*frame));
|
memset(frame, 0, sizeof(*frame));
|
||||||
/* Shifting RA into prvTaskExitError is necessary to make GDB backtrace ending inside that function.
|
|
||||||
Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */
|
/* Initialize the stack frame. */
|
||||||
frame->ra = (UBaseType_t)prvTaskExitError + 4/*size of the nop insruction at the beginning of prvTaskExitError*/;
|
extern uint32_t __global_pointer$;
|
||||||
frame->mepc = (UBaseType_t)pxCode;
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
frame->a0 = (UBaseType_t)pvParameters;
|
frame->mepc = (UBaseType_t)vPortTaskWrapper;
|
||||||
frame->gp = (UBaseType_t)&__global_pointer$;
|
frame->a0 = (UBaseType_t)pxCode;
|
||||||
|
frame->a1 = (UBaseType_t)pvParameters;
|
||||||
|
#else
|
||||||
|
frame->mepc = (UBaseType_t)pxCode;
|
||||||
|
frame->a0 = (UBaseType_t)pvParameters;
|
||||||
|
#endif // CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
|
frame->gp = (UBaseType_t)&__global_pointer$;
|
||||||
frame->tp = (UBaseType_t)threadptr;
|
frame->tp = (UBaseType_t)threadptr;
|
||||||
|
|
||||||
//TODO: IDF-2393
|
//TODO: IDF-2393
|
||||||
|
Reference in New Issue
Block a user