Skip to content

Commit 2382ad6

Browse files
committed
OS/ThreadX: Fix task stack corruption in SMP PortThreadSwitch
Move the stack swap around PortThreadSwitch into the SMP context switch path so the scheduler runs on the per-core interrupt stack rather than the outgoing task stack. This prevents the saved task stack from being touched after that task becomes runnable on another CPU, avoiding stack overwrite and other undefined failures during SMP scheduling. Also publish the selected thread through _tx_thread_current_ptr[coreid] so the restore path uses the exact thread claimed during the switch. Signed-off-by: Huaqi Fang <578567190@qq.com>
1 parent 2aba46f commit 2382ad6

3 files changed

Lines changed: 24 additions & 14 deletions

File tree

OS/ThreadX/ports_smp/nuclei/gcc/context.S

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,13 @@ eclic_msip_handler:
168168
STORE sp, 2 * REGBYTES(t0)
169169

170170
_tx_thread_save_switch:
171+
/* Switch from the thread stack to the per-core interrupt stack to avoid
172+
corrupting the thread stack during scheduling. */
173+
csrrw sp, CSR_MSCRATCHCSWL, sp
171174
jal PortThreadSwitch
175+
csrrw sp, CSR_MSCRATCHCSWL, sp
176+
/* Switch back to the saved thread stack for now; a new stack pointer will
177+
be loaded for the selected thread below. */
172178

173179
/* PortThreadSwitch has claimed and published the selected thread in
174180
_tx_thread_current_ptr[coreid]. Restore that exact thread instead of

OS/ThreadX/ports_smp/nuclei/iar/context.S

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,13 @@ eclic_msip_handler:
166166
STORE sp, 2 * REGBYTES(t0)
167167

168168
_tx_thread_save_switch:
169+
/* Switch from the thread stack to the per-core interrupt stack to avoid
170+
corrupting the thread stack during scheduling. */
171+
csrrw sp, CSR_MSCRATCHCSWL, sp
169172
jal PortThreadSwitch
173+
csrrw sp, CSR_MSCRATCHCSWL, sp
174+
/* Switch back to the saved thread stack for now; a new stack pointer will
175+
be loaded for the selected thread below. */
170176

171177
/* PortThreadSwitch has claimed and published the selected thread in
172178
_tx_thread_current_ptr[coreid]. Restore that exact thread instead of

OS/ThreadX/ports_smp/nuclei/port.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,39 +135,37 @@ void PortThreadSwitch(void)
135135
rdy_thread = _tx_thread_execute_ptr[coreid];
136136
if ((!rdy_thread) || (rdy_thread -> tx_thread_smp_core_control != 1)) {
137137
if (coreid == 0) {
138-
/* increase the timer interrupt to higher priority to enable interrupt nesting */
138+
/* Raise the timer interrupt priority temporarily so interrupt
139+
nesting remains available while searching for a ready thread. */
139140
ECLIC_SetLevelIRQ(SysTimer_IRQn, KERNEL_INTERRUPT_PRIORITY + 1);
140141
__RWMB();
141142
}
142-
/* swap task stack to interrupt stack to avoid interrupt nesting on task stack */
143-
__ASM volatile("csrrw sp, " STRINGIFY(CSR_MSCRATCHCSWL) ", sp");
144143
__RWMB();
145-
/* mcause must be saved and restore if interrupt nested */
144+
/* Save mcause/msubm because they may be overwritten when interrupts
145+
are re-enabled and nested here. */
146146
rv_csr_t mcause = __RV_CSR_READ(CSR_MCAUSE);
147147
rv_csr_t msubm = __RV_CSR_READ(CSR_MSUBM);
148148
__enable_irq();
149149
__RWMB();
150-
/* Claim the selected thread while on the interrupt stack. Publish it
151-
as current only after switching back to the task stack below. */
152-
_tx_find_ready_thread(TX_TRUE);
153-
/* disable interrupt to avoid interrupt nesting since new task handle found */
150+
rdy_thread = _tx_find_ready_thread(TX_FALSE);
151+
/* Disable interrupts again after a candidate thread has been found to
152+
prevent further nesting during the handoff. */
154153
__disable_irq();
155154
__RWMB();
156-
/* restore mcause which is necessary since interrupt nested manually by us */
155+
/* Restore mcause/msubm because nested interrupts were allowed
156+
explicitly in the search window above. */
157157
__RV_CSR_WRITE(CSR_MSUBM, msubm);
158158
__RV_CSR_WRITE(CSR_MCAUSE, mcause);
159-
/* swap interrupt stack back to task stack */
160-
__ASM volatile("csrrw sp, " STRINGIFY(CSR_MSCRATCHCSWL) ", sp");
161159
__RWMB();
162-
/* restore timer interrupt to origin kernel interrupt priority */
160+
/* Restore the timer interrupt to its normal kernel priority. */
163161
if (coreid == 0) {
164162
ECLIC_SetLevelIRQ(SysTimer_IRQn, KERNEL_INTERRUPT_PRIORITY);
165163
__RWMB();
166164
}
167165
} else {
168-
_tx_find_ready_thread(TX_TRUE);
166+
rdy_thread = _tx_find_ready_thread(TX_FALSE);
169167
}
170-
rdy_thread = _tx_thread_current_ptr[coreid];
168+
_tx_thread_current_ptr[coreid] = rdy_thread;
171169
/* Clear the execution control flag. */
172170
rdy_thread -> tx_thread_smp_core_control = 0;
173171
rdy_thread -> tx_thread_run_count ++;

0 commit comments

Comments
 (0)