Skip to content

Commit 73a9579

Browse files
Pataterbulislaw
authored andcommitted
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 cb2b91c commit 73a9579

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

rtos/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_GCC/TARGET_M3/irq_cm3.S

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

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

8294
SVC_ContextRestore:
8395
LDR R0,[R2,#TCB_SP_OFS] // Load SP
8496
LDMIA R0!,{R4-R11} // Restore R4..R11
8597
MSR PSP,R0 // Set PSP
98+
#ifdef FEATURE_UVISOR
99+
CPSIE I // The PSP has been set. Re-enable interrupts.
100+
#endif
86101
MVN LR,#~0xFFFFFFFD // Set EXC_RETURN value
87102

88103
SVC_Exit:

rtos/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_GCC/TARGET_RTOS_M4_M7/irq_cm4f.S

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

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

99111
SVC_ContextRestore:
@@ -108,6 +120,9 @@ SVC_ContextRestore:
108120
#endif
109121
LDMIA R0!,{R4-R11} // Restore R4..R11
110122
MSR PSP,R0 // Set PSP
123+
#ifdef FEATURE_UVISOR
124+
CPSIE I // The PSP has been set. Re-enable interrupts.
125+
#endif
111126

112127
SVC_Exit:
113128
BX LR // Exit from handler

rtos/TARGET_CORTEX/rtx5/RTX/Source/rtx_thread.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ void osRtxThreadListPut (os_object_t *object, os_thread_t *thread) {
166166

167167
/// Get a Thread with Highest Priority from specified Object list and remove it.
168168
/// \param[in] object generic object.
169-
/// \return thread object.
169+
/// \return thread object.
170170
os_thread_t *osRtxThreadListGet (os_object_t *object) {
171171
os_thread_t *thread;
172172

@@ -426,6 +426,17 @@ void osRtxThreadSwitch (os_thread_t *thread) {
426426
osRtxInfo.thread.run.next = thread;
427427
osRtxThreadStackCheck();
428428
EvrRtxThreadSwitched(thread);
429+
430+
if (osEventObs && osEventObs->thread_switch) {
431+
osEventObs->thread_switch(thread->context);
432+
}
433+
}
434+
435+
/// Notify the OS event observer of an imminent thread switch.
436+
void thread_switch_helper(void) {
437+
if (osEventObs && osEventObs->thread_switch) {
438+
osEventObs->thread_switch(osRtxInfo.thread.run.next->context);
439+
}
429440
}
430441

431442
/// Dispatch specified Thread or Ready Thread with Highest Priority.
@@ -804,7 +815,7 @@ static osThreadId_t svcRtxThreadNew (osThreadFunc_t func, void *argument, const
804815
} else {
805816
EvrRtxThreadError(NULL, (int32_t)osErrorNoMemory);
806817
}
807-
818+
808819
if (thread != NULL) {
809820
osRtxThreadDispatch(thread);
810821
}

0 commit comments

Comments
 (0)