Explorar o código

freertos: Xtensa FreeRTOS saves threadptr in solicited stack frame

The Xtensa FreeRTOS port does not save the threadptr register when
doing a voluntary yield. This can result in a crash when multiple
tasks used the threadptr register and call "taskYIELD()".

This commit adds the threadptr register to the solicited stack frame.
Darian Leung %!s(int64=3) %!d(string=hai) anos
pai
achega
434287fc8b

+ 8 - 0
components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S

@@ -468,6 +468,10 @@ _frxt_dispatch:
 .L_frxt_dispatch_sol:
 
     /* Solicited stack frame. Restore minimal context and return from vPortYield(). */
+    #if XCHAL_HAVE_THREADPTR
+    l32i    a2,  sp, XT_SOL_THREADPTR
+    wur.threadptr a2
+    #endif
     l32i    a3,  sp, XT_SOL_PS
     #ifdef __XTENSA_CALL0_ABI__
     l32i    a12, sp, XT_SOL_A12
@@ -555,6 +559,10 @@ vPortYield:
     rsr     a2,  PS
     s32i    a0,  sp, XT_SOL_PC
     s32i    a2,  sp, XT_SOL_PS
+    #if XCHAL_HAVE_THREADPTR
+    rur.threadptr a2
+    s32i    a2,  sp, XT_SOL_THREADPTR
+    #endif
     #ifdef __XTENSA_CALL0_ABI__
     s32i    a12, sp, XT_SOL_A12         /* save callee-saved registers      */
     s32i    a13, sp, XT_SOL_A13

+ 8 - 0
components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S

@@ -446,6 +446,10 @@ _frxt_dispatch:
 .L_frxt_dispatch_sol:
 
     /* Solicited stack frame. Restore minimal context and return from vPortYield(). */
+    #if XCHAL_HAVE_THREADPTR
+    l32i    a2,  sp, XT_SOL_THREADPTR
+    wur.threadptr a2
+    #endif
     l32i    a3,  sp, XT_SOL_PS
     #ifdef __XTENSA_CALL0_ABI__
     l32i    a12, sp, XT_SOL_A12
@@ -533,6 +537,10 @@ vPortYield:
     rsr     a2,  PS
     s32i    a0,  sp, XT_SOL_PC
     s32i    a2,  sp, XT_SOL_PS
+    #if XCHAL_HAVE_THREADPTR
+    rur.threadptr a2
+    s32i    a2,  sp, XT_SOL_THREADPTR
+    #endif
     #ifdef __XTENSA_CALL0_ABI__
     s32i    a12, sp, XT_SOL_A12         /* save callee-saved registers      */
     s32i    a13, sp, XT_SOL_A13

+ 18 - 2
components/xtensa/include/xtensa/xtensa_context.h

@@ -193,6 +193,14 @@ STRUCT_END(XtExcFrame)
   by the callee according to the compiler's ABI conventions, some space to save
   the return address for returning to the caller, and the caller's PS register.
 
+  Note: Although the xtensa ABI considers the threadptr as "global" across
+  functions (meanig it is neither caller or callee saved), it is treated as a
+  callee-saved register in a solicited stack frame. This omits the need for the
+  OS to include extra logic to save "global" registers on each context switch.
+  Only the threadptr register is treated as callee-saved, as all other NCP
+  (non-coprocessor extra) registers are caller-saved. See "tie.h" for more
+  details.
+
   For Windowed ABI, this stack frame includes the caller's base save area.
 
   Note on XT_SOL_EXIT field:
@@ -209,7 +217,11 @@ STRUCT_BEGIN
 STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit)
 STRUCT_FIELD (long, 4, XT_SOL_PC,   pc)
 STRUCT_FIELD (long, 4, XT_SOL_PS,   ps)
-STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)
+#if XCHAL_HAVE_THREADPTR
+STRUCT_FIELD (long, 4, XT_SOL_THREADPTR, threadptr)
+#else
+STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)   /* Dummy register for 16-byte alignment */
+#endif
 STRUCT_FIELD (long, 4, XT_SOL_A12,  a12)    /* should be on 16-byte alignment */
 STRUCT_FIELD (long, 4, XT_SOL_A13,  a13)
 STRUCT_FIELD (long, 4, XT_SOL_A14,  a14)
@@ -218,7 +230,11 @@ STRUCT_FIELD (long, 4, XT_SOL_A15,  a15)
 STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit)
 STRUCT_FIELD (long, 4, XT_SOL_PC,   pc)
 STRUCT_FIELD (long, 4, XT_SOL_PS,   ps)
-STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)
+#if XCHAL_HAVE_THREADPTR
+STRUCT_FIELD (long, 4, XT_SOL_THREADPTR, threadptr)
+#else
+STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)   /* Dummy register for 16-byte alignment */
+#endif
 STRUCT_FIELD (long, 4, XT_SOL_A0,   a0)    /* should be on 16-byte alignment */
 STRUCT_FIELD (long, 4, XT_SOL_A1,   a1)
 STRUCT_FIELD (long, 4, XT_SOL_A2,   a2)