mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04: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:
commit
83e2cf1a68
@ -247,8 +247,8 @@ void esp_panic_handler(panic_info_t *info)
|
||||
*
|
||||
* ----------------------------------------------------------------------------------------
|
||||
* core - core where exception was triggered
|
||||
* exception - what kind of exception occured
|
||||
* description - a short description regarding the exception that occured
|
||||
* exception - what kind of exception occurred
|
||||
* description - a short description regarding the exception that occurred
|
||||
* details - more details about the exception
|
||||
* state - processor state like register contents, and backtrace
|
||||
* 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_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
|
||||
panic_print_str("\r\nELF file SHA256: ");
|
||||
char sha256_buf[65];
|
||||
@ -349,10 +357,6 @@ void esp_panic_handler(panic_info_t *info)
|
||||
} else {
|
||||
disable_all_wdts();
|
||||
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
|
||||
esp_core_dump_to_flash(info);
|
||||
#endif
|
||||
|
@ -515,30 +515,29 @@ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
|
||||
#endif //( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
// ------------------------ Stack --------------------------
|
||||
|
||||
__attribute__((noreturn)) static void _prvTaskExitError(void)
|
||||
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||
/**
|
||||
* 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
|
||||
its caller as there is nothing to return to. If a task wants to exit it
|
||||
should instead call vTaskDelete( NULL ).
|
||||
|
||||
Artificially force an assert() to be triggered if configASSERT() is
|
||||
defined, then stop here so application writers can catch the error. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
abort();
|
||||
asm volatile(".cfi_undefined ra\n");
|
||||
extern void __attribute__((noreturn)) panic_abort(const char *details);
|
||||
static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0";
|
||||
pxCode(pvParameters);
|
||||
//FreeRTOS tasks should not return. Log the task name and abort.
|
||||
char *pcTaskName = pcTaskGetName(NULL);
|
||||
/* We cannot use s(n)printf because it is in flash */
|
||||
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)
|
||||
{
|
||||
@ -602,11 +601,16 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
||||
sp -= RV_STK_FRMSZ;
|
||||
RvExcFrame *frame = (RvExcFrame *)sp;
|
||||
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. */
|
||||
frame->ra = (UBaseType_t)prvTaskExitError + 4/*size of the nop insruction at the beginning of prvTaskExitError*/;
|
||||
|
||||
/* Initialize the stack frame. */
|
||||
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||
frame->mepc = (UBaseType_t)vPortTaskWrapper;
|
||||
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;
|
||||
|
||||
|
@ -113,31 +113,29 @@ void vPortEndScheduler(void)
|
||||
}
|
||||
|
||||
// ------------------------ Stack --------------------------
|
||||
|
||||
__attribute__((noreturn)) static void _prvTaskExitError(void)
|
||||
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||
/**
|
||||
* 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
|
||||
its caller as there is nothing to return to. If a task wants to exit it
|
||||
should instead call vTaskDelete( NULL ).
|
||||
|
||||
Artificially force an assert() to be triggered if configASSERT() is
|
||||
defined, then stop here so application writers can catch the error. */
|
||||
configASSERT(uxCriticalNesting == ~0UL);
|
||||
portDISABLE_INTERRUPTS();
|
||||
abort();
|
||||
asm volatile(".cfi_undefined ra\n");
|
||||
extern void __attribute__((noreturn)) panic_abort(const char *details);
|
||||
static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0";
|
||||
pxCode(pvParameters);
|
||||
//FreeRTOS tasks should not return. Log the task name and abort.
|
||||
char *pcTaskName = pcTaskGetName(NULL);
|
||||
/* We cannot use s(n)printf because it is in flash */
|
||||
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)
|
||||
{
|
||||
@ -201,11 +199,17 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
||||
sp -= RV_STK_FRMSZ;
|
||||
RvExcFrame *frame = (RvExcFrame *)sp;
|
||||
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. */
|
||||
frame->ra = (UBaseType_t)prvTaskExitError + 4/*size of the nop insruction at the beginning of prvTaskExitError*/;
|
||||
|
||||
/* Initialize the stack frame. */
|
||||
extern uint32_t __global_pointer$;
|
||||
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||
frame->mepc = (UBaseType_t)vPortTaskWrapper;
|
||||
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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user