内核移植(六)--中断处理

中断处理 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 

你可能感兴趣的:(RT-Thread,内核移植,中断处理,PendSV中断)