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.
This commit is contained in:
Darian Leung 2022-07-04 18:04:11 +08:00
parent c9140caf8c
commit c26d2ad132
2 changed files with 26 additions and 2 deletions

View File

@ -449,6 +449,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
@ -536,6 +540,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

View File

@ -188,6 +188,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 (meaning 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:
@ -204,7 +212,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)
@ -213,7 +225,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)