Skip to content

Commit 778d682

Browse files
committed
RTX5: uVisor: Switch threads very carefully
uVisor doesn't set the PSP of the target thread. The RTOS sets the PSP of the target thread from the target thread's TCB. However, when interrupts of higher priority than PendSV happen between the call to uVisor to switch boxes, and the RTOS setting PSP, the uVisor vIRQ interrupt handler will attempt to use an invalid PSP (the PSP from before the box and thread switch). This leads to a crash. Make box and thread switching atomic by disabling interrupts immediately before the box switching until immediately after the new PSP is set.
1 parent 0da63ee commit 778d682

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

rtos/rtx5/TARGET_CORTEX_M/TARGET_M3/TOOLCHAIN_GCC/irq_cm3.S

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,27 @@ SVC_ContextSave:
7373
STR R12,[R1,#TCB_SP_OFS] // Store SP
7474

7575
SVC_ContextSwitch:
76+
#ifdef FEATURE_UVISOR
77+
CPSID I // The call to the thread switch helper and PSP loading must be atomic.
78+
#endif
79+
/* The call to thread_switch_helper can clobber R2 and R3, but we don't
80+
* want to clobber R2 or R3. We can't save R2 and R3 to the stack (as
81+
* the stack we save them onto is likely to be inaccessible after the
82+
* call to thread_switch_helper). So, we just re-obtain the values from
83+
* osRtxInfo again. */
84+
BL thread_switch_helper
85+
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
86+
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
87+
7688
STR R2,[R3] // osRtxInfo.thread.run: curr = next
7789

7890
SVC_ContextRestore:
7991
LDR R0,[R2,#TCB_SP_OFS] // Load SP
8092
LDMIA R0!,{R4-R11} // Restore R4..R11
8193
MSR PSP,R0 // Set PSP
94+
#ifdef FEATURE_UVISOR
95+
CPSIE I // The PSP has been set. Re-enable interrupts.
96+
#endif
8297
MVN LR,#~0xFFFFFFFD // Set EXC_RETURN value
8398

8499
SVC_Exit:

rtos/rtx5/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/irq_cm4f.S

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ SVC_ContextSave:
9191
STRB LR, [R1,#TCB_SF_OFS] // Store stack frame information
9292

9393
SVC_ContextSwitch:
94+
#ifdef FEATURE_UVISOR
95+
CPSID I // The call to the thread switch helper and PSP loading must be atomic.
96+
#endif
97+
/* The call to thread_switch_helper can clobber R2 and R3, but we don't
98+
* want to clobber R2 or R3. We can't save R2 and R3 to the stack (as
99+
* the stack we save them onto is likely to be inaccessible after the
100+
* call to thread_switch_helper). So, we just re-obtain the values from
101+
* osRtxInfo again. */
102+
BL thread_switch_helper
103+
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
104+
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
105+
94106
STR R2,[R3] // osRtxInfo.thread.run: curr = next
95107

96108
SVC_ContextRestore:
@@ -105,6 +117,9 @@ SVC_ContextRestore:
105117
#endif
106118
LDMIA R0!,{R4-R11} // Restore R4..R11
107119
MSR PSP,R0 // Set PSP
120+
#ifdef FEATURE_UVISOR
121+
CPSIE I // The PSP has been set. Re-enable interrupts.
122+
#endif
108123

109124
SVC_Exit:
110125
BX LR // Exit from handler

rtos/rtx5/TARGET_CORTEX_M/rtx_thread.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,12 @@ void osRtxThreadSwitch (os_thread_t *thread) {
426426
osRtxInfo.thread.run.next = thread;
427427
osRtxThreadStackCheck();
428428
EvrRtxThreadSwitch(thread);
429+
}
429430

431+
/// Notify the OS event observer of an imminent thread switch.
432+
void thread_switch_helper(void) {
430433
if (osEventObs && osEventObs->thread_switch) {
431-
osEventObs->thread_switch(thread->context);
434+
osEventObs->thread_switch(osRtxInfo.thread.run.next->context);
432435
}
433436
}
434437

0 commit comments

Comments
 (0)