|
|
@@ -114,31 +114,6 @@ void vPortEndScheduler(void)
|
|
|
|
|
|
// ------------------------ Stack --------------------------
|
|
|
|
|
|
-__attribute__((noreturn)) static void _prvTaskExitError(void)
|
|
|
-{
|
|
|
- /* 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();
|
|
|
-}
|
|
|
-
|
|
|
-__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();
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* @brief Align stack pointer in a downward growing stack
|
|
|
*
|
|
|
@@ -220,6 +195,29 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u
|
|
|
return uxStackPointer;
|
|
|
}
|
|
|
|
|
|
+#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)
|
|
|
+{
|
|
|
+ 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
|
|
|
+
|
|
|
/**
|
|
|
* @brief Initialize the task's starting interrupt stack frame
|
|
|
*
|
|
|
@@ -248,16 +246,16 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackFrame(UBaseType_t uxStackPointer,
|
|
|
RvExcFrame *frame = (RvExcFrame *)uxStackPointer;
|
|
|
memset(frame, 0, sizeof(RvExcFrame));
|
|
|
|
|
|
- /*
|
|
|
- Initialize the stack frame.
|
|
|
-
|
|
|
- Note: Shifting RA into prvTaskExitError is necessary to make the GDB backtrace terminate inside that function.
|
|
|
- Otherwise, the backtrace will end in the function located just before prvTaskExitError in the address space.
|
|
|
- */
|
|
|
+ /* Initialize the stack frame. */
|
|
|
extern uint32_t __global_pointer$;
|
|
|
- frame->ra = (UBaseType_t)prvTaskExitError + 4; // size of the nop instruction at the beginning of prvTaskExitError
|
|
|
- frame->mepc = (UBaseType_t)pxCode;
|
|
|
- frame->a0 = (UBaseType_t)pvParameters;
|
|
|
+ #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_reg_init;
|
|
|
|