中断处理 PendSV_Handler
函数
PendSV_Handler()
函数是真正实现线程上下文切换的地方
PendSV_Handler PROC ;PROC 定义子程序的开始
EXPORT PendSV_Handler ;声明一个标号具有全局属性
;失能中断,为了保护上下文切换不被中断
MRS r2, PRIMASK ;MRS 加载特殊功能寄存器的值到通用寄存器
CPSID I ;失能中断,为了保护上下文切换不被中断
;获取中断标志位,看看是否为 0
LDR r0, =rt_thread_switch_interrupt_flag ;加载 rt_thread_switch_interrupt_flag 变量的地址到 r0 寄存器
LDR r1, [r0] ;加载 rt_thread_switch_interrupt_flag 的值到 r1 寄存器 *r0 = r1
CBZ r1, pendsv_exit ;判断 r1 是否为 0 ,为 0 则跳转到 pendsv_exit,表示不需要进行线程切换,退出 PendSV_Handler 函数 CBZ:比较,如果结果为0就转移
; r1 不为 0 ,则清 0
MOV r1, #0x00
STR r1, [r0] ;将 r1 的值存储到 rt_thread_switch_interrupt_flag 变量, 即清 0
;判断 rt_interrupt_from_thread 的值是否为 0
LDR r0, =rt_interrupt_from_thread ;加载 rt_interrupt_from_thread 变量的地址到 r0 寄存器
LDR r1, [r0] ;加载 rt_interrupt_from_thread 变量的值到 r1 寄存器 *r0 = r1
CBZ r1, switch_to_thread ;判断 r1 是否为 0,为 0 则跳转到 switch_to_thread, 第一次线程切换时 rt_interrupt_from_thread 肯定为 0,则跳转到 switch_to_thread
;**************************************上文保存*******************************************
;当进入 PendSV 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 寄存器rt_interrupt_to_thread 是一个全局变量,里面存的是线程栈指针 SP 的指针
LDR r1, [r1] ;加载 rt_interrupt_to_thread 变量的值到 r1 寄存器,即 sp 指针的指针
LDR r1, [r1] ;加载 sp 变量的值到 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
BX lr ;异常返回,这个时候接下来将要运行的线程栈中的剩下内容将会自动加载到 CPU 寄存器:xPSR,PC(线程入口地址),R14,R12,R3,R2,R1,R0(线程的形参)同时 PSP 的值也将更新,即指向线程栈的栈顶。
ENDP