Skip to content

Commit 13248a2

Browse files
committed
OS/ThreadX: Fix SMP scheduler SWI context handling
Track normal IRQ nesting in the per-core ThreadX system state, while keeping the scheduler SWI path separate from normal ISR dispatch. Also make PortThreadSwitch claim the selected ready thread and restore that same thread from _tx_thread_current_ptr, avoiding a later reload of _tx_thread_execute_ptr that may have been changed by another hart. Signed-off-by: Huaqi Fang <578567190@qq.com>
1 parent 5e8721b commit 13248a2

5 files changed

Lines changed: 101 additions & 39 deletions

File tree

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

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ _tx_thread_schedule:
6363
addi t0, t0, 1
6464
STORE t0, 1 * REGBYTES(a0)
6565

66-
LOAD sp, 2 * REGBYTES(a0) /* Read sp from _tx_thread_execute_ptr[coreid] -> tx_thread_stack_ptr */
66+
LOAD sp, 2 * REGBYTES(a0) /* Read sp from selected thread -> tx_thread_stack_ptr */
6767
/* Pop PC from stack and set MEPC */
6868
LOAD t0, 0 * REGBYTES(sp)
6969
csrw CSR_MEPC, t0
@@ -147,10 +147,12 @@ eclic_msip_handler:
147147
/* Push mstatus to stack */
148148
csrr t0, CSR_MSTATUS
149149
STORE t0, (portRegNum - 1) * REGBYTES(sp)
150+
/* Store last pc to thread stack */
151+
csrr t0, CSR_MEPC
152+
STORE t0, 0(sp)
150153

151154
/* Push additional registers */
152155

153-
/* If _tx_thread_current_ptr[coreid] is null, no sp need to be saved */
154156
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
155157
la t0, _tx_thread_current_ptr
156158
csrr t1, CSR_MHARTID
@@ -160,27 +162,30 @@ eclic_msip_handler:
160162
la t0, _tx_thread_current_ptr
161163
#endif
162164
LOAD t0, 0(t0)
163-
beqz t0, _tx_thread_switch
165+
/* If _tx_thread_current_ptr[coreid] is null, no sp need to be saved */
166+
beqz t0, _tx_thread_save_switch
164167
/* Store sp to task stack to _tx_thread_current_ptr -> tx_thread_stack_ptr */
165168
STORE sp, 2 * REGBYTES(t0)
166-
/* Store last pc to thread stack */
167-
csrr t0, CSR_MEPC
168-
STORE t0, 0(sp)
169169

170-
_tx_thread_switch:
170+
_tx_thread_save_switch:
171171
jal PortThreadSwitch
172172

173-
/* Switch task context to _tx_thread_execute_ptr[coreid] */
173+
/* PortThreadSwitch has claimed and published the selected thread in
174+
_tx_thread_current_ptr[coreid]. Restore that exact thread instead of
175+
reloading _tx_thread_execute_ptr, which may be changed by another hart. */
174176
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
175-
la t0, _tx_thread_execute_ptr
177+
la t0, _tx_thread_current_ptr
176178
csrr t1, CSR_MHARTID
177179
slli t1, t1, LOG_REGBYTES
178180
add t0, t0, t1
179181
#else
180-
la t0, _tx_thread_execute_ptr
182+
la t0, _tx_thread_current_ptr
181183
#endif
182184
LOAD t0, 0(t0)
185+
/* If _tx_thread_current_ptr[coreid] is null, no sp need to be restored */
186+
beqz t0, _tx_thread_restore_switch
183187
LOAD sp, 2 * REGBYTES(t0)
188+
_tx_thread_restore_switch:
184189

185190
/* Pop PC from stack and set MEPC */
186191
LOAD t0, 0 * REGBYTES(sp)

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515
csrc CSR_MSTATUS, MSTATUS_MIE
1616
.endm
1717

18+
/* Update ThreadX SMP per-core ISR nesting state.
19+
* This macro must be called after SAVE_CONTEXT because it clobbers t0-t2.
20+
*/
21+
.macro UPDATE_THREADX_SYSTEM_STATE delta
22+
la t0, _tx_thread_system_state
23+
csrr t1, CSR_MHARTID
24+
slli t1, t1, LOG_REGBYTES
25+
add t0, t0, t1
26+
LOAD t2, 0(t0)
27+
addi t2, t2, \delta
28+
STORE t2, 0(t0)
29+
.endm
30+
1831
/**
1932
* \brief Macro for context save
2033
* \details
@@ -202,6 +215,11 @@ irq_entry:
202215
/* Save the necessary CSR registers */
203216
SAVE_CSR_CONTEXT
204217

218+
/* Mark this core as being in a normal IRQ handler.
219+
* eclic_msip_handler is the scheduler SWI path and is handled separately.
220+
*/
221+
UPDATE_THREADX_SYSTEM_STATE 1
222+
205223
/* This special CSR read/write operation, which is actually
206224
* claim the CLIC to find its pending highest ID, if the ID
207225
* is not 0, then automatically enable the mstatus.MIE, and
@@ -212,6 +230,11 @@ irq_entry:
212230
/* Critical section with interrupts disabled */
213231
DISABLE_MIE
214232

233+
/* All nested IRQ work claimed by JALMNXTI is done; leave ThreadX ISR context
234+
* before restoring the interrupted context.
235+
*/
236+
UPDATE_THREADX_SYSTEM_STATE -1
237+
215238
/* Restore the necessary CSR registers */
216239
RESTORE_CSR_CONTEXT
217240
/* Restore the caller saving registers (context) */
@@ -235,4 +258,3 @@ default_intexc_handler:
235258
j 1b
236259

237260
.size default_intexc_handler, . - default_intexc_handler
238-

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

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ _per_cpu_init_sp_fin:
6565
addi t0, t0, 1
6666
STORE t0, 1 * REGBYTES(a0)
6767

68-
LOAD sp, 2 * REGBYTES(a0) /* Read sp from _tx_thread_execute_ptr[coreid] -> tx_thread_stack_ptr */
68+
LOAD sp, 2 * REGBYTES(a0) /* Read sp from selected thread -> tx_thread_stack_ptr */
6969
/* Pop PC from stack and set MEPC */
7070
LOAD t0, 0 * REGBYTES(sp)
7171
csrw CSR_MEPC, t0
@@ -145,10 +145,12 @@ eclic_msip_handler:
145145
/* Push mstatus to stack */
146146
csrr t0, CSR_MSTATUS
147147
STORE t0, (portRegNum - 1) * REGBYTES(sp)
148+
/* Store last pc to thread stack */
149+
csrr t0, CSR_MEPC
150+
STORE t0, 0(sp)
148151

149152
/* Push additional registers */
150153

151-
/* If _tx_thread_current_ptr[coreid] is null, no sp need to be saved */
152154
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
153155
la t0, _tx_thread_current_ptr
154156
csrr t1, CSR_MHARTID
@@ -158,27 +160,30 @@ eclic_msip_handler:
158160
la t0, _tx_thread_current_ptr
159161
#endif
160162
LOAD t0, 0(t0)
161-
beqz t0, _tx_thread_switch
163+
/* If _tx_thread_current_ptr[coreid] is null, no sp need to be saved */
164+
beqz t0, _tx_thread_save_switch
162165
/* Store sp to task stack to _tx_thread_current_ptr -> tx_thread_stack_ptr */
163166
STORE sp, 2 * REGBYTES(t0)
164-
/* Store last pc to thread stack */
165-
csrr t0, CSR_MEPC
166-
STORE t0, 0(sp)
167167

168-
_tx_thread_switch:
168+
_tx_thread_save_switch:
169169
jal PortThreadSwitch
170170

171-
/* Switch task context to _tx_thread_execute_ptr[coreid] */
171+
/* PortThreadSwitch has claimed and published the selected thread in
172+
_tx_thread_current_ptr[coreid]. Restore that exact thread instead of
173+
reloading _tx_thread_execute_ptr, which may be changed by another hart. */
172174
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
173-
la t0, _tx_thread_execute_ptr
175+
la t0, _tx_thread_current_ptr
174176
csrr t1, CSR_MHARTID
175177
slli t1, t1, LOG_REGBYTES
176178
add t0, t0, t1
177179
#else
178-
la t0, _tx_thread_execute_ptr
180+
la t0, _tx_thread_current_ptr
179181
#endif
180182
LOAD t0, 0(t0)
183+
/* If _tx_thread_current_ptr[coreid] is null, no sp need to be restored */
184+
beqz t0, _tx_thread_restore_switch
181185
LOAD sp, 2 * REGBYTES(t0)
186+
_tx_thread_restore_switch:
182187

183188
/* Pop PC from stack and set MEPC */
184189
LOAD t0, 0 * REGBYTES(sp)

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ DISABLE_MIE MACRO
55
csrci CSR_MSTATUS, MSTATUS_MIE
66
ENDM
77

8+
/* Update ThreadX SMP per-core ISR nesting state.
9+
* This macro must be called after SAVE_CONTEXT because it clobbers t0-t2.
10+
*/
11+
UPDATE_THREADX_SYSTEM_STATE MACRO delta
12+
la t0, _tx_thread_system_state
13+
csrr t1, CSR_MHARTID
14+
slli t1, t1, LOG_REGBYTES
15+
add t0, t0, t1
16+
LOAD t2, 0(t0)
17+
addi t2, t2, delta
18+
STORE t2, 0(t0)
19+
ENDM
20+
821
SAVE_CONTEXT MACRO
922
#if defined(ECLIC_HW_CTX_AUTO) && defined(CFG_HAS_ECLICV2)
1023
#else
@@ -97,6 +110,7 @@ RESTORE_CSR_CONTEXT MACRO
97110
PUBLIC exc_entry, irq_entry, default_intexc_handler
98111
PUBLIC Undef_Handler
99112
EXTERN core_exception_handler
113+
EXTERN _tx_thread_system_state
100114
SECTION `.text`:CODE:NOROOT(2)
101115
CODE
102116

@@ -162,6 +176,11 @@ irq_entry:
162176
/* Save the necessary CSR registers */
163177
SAVE_CSR_CONTEXT
164178

179+
/* Mark this core as being in a normal IRQ handler.
180+
* eclic_msip_handler is the scheduler SWI path and is handled separately.
181+
*/
182+
UPDATE_THREADX_SYSTEM_STATE 1
183+
165184
/* This special CSR read/write operation, which is actually
166185
* claim the CLIC to find its pending highest ID, if the ID
167186
* is not 0, then automatically enable the mstatus.MIE, and
@@ -172,6 +191,11 @@ irq_entry:
172191
/* Critical section with interrupts disabled */
173192
DISABLE_MIE
174193

194+
/* All nested IRQ work claimed by JALMNXTI is done; leave ThreadX ISR context
195+
* before restoring the interrupted context.
196+
*/
197+
UPDATE_THREADX_SYSTEM_STATE -1
198+
175199
/* Restore the necessary CSR registers */
176200
RESTORE_CSR_CONTEXT
177201
/* Restore the caller saving registers (context) */

OS/ThreadX/ports_smp/nuclei/port.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,27 @@ TX_THREAD* _tx_find_ready_thread(UINT set_current)
9393
// Task Switch code called in eclic_msip_handler
9494
void PortThreadSwitch(void)
9595
{
96+
TX_THREAD *rdy_thread;
97+
UINT coreid = _tx_thread_smp_core_get();
98+
99+
if (_tx_thread_preempt_disable != 0) {
100+
if (_tx_thread_smp_protection.tx_thread_smp_protect_core == coreid) {
101+
SysTimer_ClearSWIRQ();
102+
}
103+
__RWMB();
104+
return;
105+
}
106+
96107
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
97108
_tx_execution_thread_exit();
98109
#endif
99-
TX_THREAD *rdy_thread;
100-
UINT coreid = _tx_thread_smp_core_get();
110+
111+
/* Acknowledge the interrupt that brought us here before scheduling.
112+
Any SWI raised after this point represents a new scheduling request
113+
and must remain pending for the restored thread. */
114+
SysTimer_ClearSWIRQ();
115+
__RWMB();
116+
101117
/*
102118
* Magic idle task emulation for threadx
103119
* ThreadX don't have idle task, so _tx_thread_execute_ptr could be NULL
@@ -131,13 +147,9 @@ void PortThreadSwitch(void)
131147
rv_csr_t msubm = __RV_CSR_READ(CSR_MSUBM);
132148
__enable_irq();
133149
__RWMB();
134-
/*
135-
* Do not touch the local rdy_thread result here.
136-
* After switching to the interrupt stack, let the scheduler helper
137-
* finish updating the execute pointer for this core, then reload the
138-
* chosen thread after the task stack is restored.
139-
*/
140-
_tx_find_ready_thread(TX_FALSE);
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);
141153
/* disable interrupt to avoid interrupt nesting since new task handle found */
142154
__disable_irq();
143155
__RWMB();
@@ -152,19 +164,13 @@ void PortThreadSwitch(void)
152164
ECLIC_SetLevelIRQ(SysTimer_IRQn, KERNEL_INTERRUPT_PRIORITY);
153165
__RWMB();
154166
}
155-
__RWMB();
156-
/* Now the task stack is restored, so it is safe to reload rdy_thread. */
157-
rdy_thread = _tx_thread_execute_ptr[coreid];
158167
} else {
159-
rdy_thread = _tx_find_ready_thread(TX_FALSE);
168+
_tx_find_ready_thread(TX_TRUE);
160169
}
161-
170+
rdy_thread = _tx_thread_current_ptr[coreid];
162171
/* Clear the execution control flag. */
163172
rdy_thread -> tx_thread_smp_core_control = 0;
164-
_tx_thread_current_ptr[coreid] = rdy_thread;
165-
_tx_thread_current_ptr[coreid] -> tx_thread_run_count ++;
166-
/* Clear Software IRQ, A MUST */
167-
SysTimer_ClearSWIRQ();
173+
rdy_thread -> tx_thread_run_count ++;
168174
__RWMB();
169175
}
170176

0 commit comments

Comments
 (0)