mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
0da63eef2b
commit
778d6822bf
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue