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.
pull/4295/head
Jaeden Amero 2017-05-25 09:48:04 +01:00
parent 0da63eef2b
commit 778d6822bf
3 changed files with 34 additions and 1 deletions

View File

@ -73,12 +73,27 @@ SVC_ContextSave:
STR R12,[R1,#TCB_SP_OFS] // Store SP
SVC_ContextSwitch:
#ifdef FEATURE_UVISOR
CPSID I // The call to the thread switch helper and PSP loading must be atomic.
#endif
/* The call to thread_switch_helper can clobber R2 and R3, but we don't
* want to clobber R2 or R3. We can't save R2 and R3 to the stack (as
* the stack we save them onto is likely to be inaccessible after the
* call to thread_switch_helper). So, we just re-obtain the values from
* osRtxInfo again. */
BL thread_switch_helper
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
STR R2,[R3] // osRtxInfo.thread.run: curr = next
SVC_ContextRestore:
LDR R0,[R2,#TCB_SP_OFS] // Load SP
LDMIA R0!,{R4-R11} // Restore R4..R11
MSR PSP,R0 // Set PSP
#ifdef FEATURE_UVISOR
CPSIE I // The PSP has been set. Re-enable interrupts.
#endif
MVN LR,#~0xFFFFFFFD // Set EXC_RETURN value
SVC_Exit:

View File

@ -91,6 +91,18 @@ SVC_ContextSave:
STRB LR, [R1,#TCB_SF_OFS] // Store stack frame information
SVC_ContextSwitch:
#ifdef FEATURE_UVISOR
CPSID I // The call to the thread switch helper and PSP loading must be atomic.
#endif
/* The call to thread_switch_helper can clobber R2 and R3, but we don't
* want to clobber R2 or R3. We can't save R2 and R3 to the stack (as
* the stack we save them onto is likely to be inaccessible after the
* call to thread_switch_helper). So, we just re-obtain the values from
* osRtxInfo again. */
BL thread_switch_helper
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
STR R2,[R3] // osRtxInfo.thread.run: curr = next
SVC_ContextRestore:
@ -105,6 +117,9 @@ SVC_ContextRestore:
#endif
LDMIA R0!,{R4-R11} // Restore R4..R11
MSR PSP,R0 // Set PSP
#ifdef FEATURE_UVISOR
CPSIE I // The PSP has been set. Re-enable interrupts.
#endif
SVC_Exit:
BX LR // Exit from handler

View File

@ -426,9 +426,12 @@ void osRtxThreadSwitch (os_thread_t *thread) {
osRtxInfo.thread.run.next = thread;
osRtxThreadStackCheck();
EvrRtxThreadSwitch(thread);
}
/// Notify the OS event observer of an imminent thread switch.
void thread_switch_helper(void) {
if (osEventObs && osEventObs->thread_switch) {
osEventObs->thread_switch(thread->context);
osEventObs->thread_switch(osRtxInfo.thread.run.next->context);
}
}