; *-----------------------------------------------------------------------
; * void PendSV_Handler(void);
; * r0 --> switch from thread stack
; * r1 --> switch to thread stack
; * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
; *-----------------------------------------------------------------------
PendSV_Handler PROC
EXPORT PendSV_Handler
MRS r2, PRIMASK ; 失能中断,为了保护上下文切换不被中断
CPSID I
LDR r0, =rt_thread_switch_interrupt_flag ;加载rt_thread_switch_interrupt_flag 的地址到r0
LDR r1, [r0] ; 加载rt_thread_switch_interrupt_flag 的值到r1
CBZ r1, pendsv_exit ;判断r1 是否为0,为0 则跳转到pendsv_exit
MOV r1, #0x00 ; r1 不为0 则清0
STR r1, [r0] ; 将r1 的值存储到rt_thread_switch_interrupt_flag,即清0
LDR r0, =rt_interrupt_from_thread ; 加载rt_interrupt_from_thread 的地址到r0
LDR r1, [r0] ; 加载rt_interrupt_from_thread 的值到r1
CBZ r1, switch_to_thread ; 判断r1 是否为0,为0 则跳转到switch_to_thread ,第一次线程切换时肯定为0,则跳转到switch_to_thread
;================================================================================================
;上文保存
;================================================================================================
; 当进入PendSVC Handler 时,上一个线程运行的环境即:
; xPSR,PC(线程入口地址),R14,R12,R3,R2,R1,R0(线程的形参)
; 这些CPU 寄存器的值会自动保存到线程的栈中,剩下的r4~r11 需要手动保存
MRS r1, psp ; 获取线程栈指针到r1
STMFD r1!, {r4 - r11} ; 将CPU 寄存器r4~r11 的值存储到r1 指向的地址(每操作一次地址将递减一次)
LDR r0, [r0] ; 加载r0 指向值到r0,即r0=rt_interrupt_from_thread
STR r1, [r0] ; 将r1 的值存储到r0,即更新线程栈sp
;========================================================================================================
;下文切换
;========================================================================================================
switch_to_thread
LDR r1, =rt_interrupt_to_thread ; 加载rt_interrupt_to_thread 的地址到r1, 它 是一个全局变量,里面存的是线程栈指针SP 的指针
LDR r1, [r1] ; 加载rt_interrupt_to_thread 的值到r1,即sp 指针的指针
LDR r1, [r1] ; 加载rt_interrupt_to_thread 的值到r1,即sp
LDMFD r1!, {r4 - r11} ; 将线程栈指针r1(操作之前先递减) 指向的内容加载到CPU 寄存器r4~r11
MSR psp, r1 ; 将线程栈指针更新到PSP
pendsv_exit
MSR PRIMASK, r2 ; 恢复中断
ORR lr, lr, #0x04 ; 确保异常返回使用的栈指针是PSP,即LR 寄存器的位2 要为1
; 异常返回,这个时候栈中的剩下内容将会自动加载到CPU 寄存器:
; xPSR,PC(线程入口地址),R14,R12,R3,R2,R1,R0(线程的形参)
; 同时PSP 的值也将更新,即指向线程栈的栈顶
BX lr
ENDP ; PendSV_Handler 子程序结束
|