RT-Thread内核移植关键代码解析(3) ---- 实现 rt_hw_context_switch_to()

一、源码

rt_hw_context_switch_to()没有来源线程,切换到目标线程,在调度器启动第一个线程的时候被调用。只使用一次。其执行逻辑流程图如下所示:

RT-Thread内核移植关键代码解析(3) ---- 实现 rt_hw_context_switch_to()_第1张图片

其采用汇编语言来实现,如下所示:

;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to    PROC
    EXPORT rt_hw_context_switch_to
    ; set to thread
    LDR     r1, =rt_interrupt_to_thread
    STR     r0, [r1]

    ; set from thread to 0
    LDR     r1, =rt_interrupt_from_thread
    MOV     r0, #0x0
    STR     r0, [r1]

    ; set interrupt flag to 1
    LDR     r1, =rt_thread_switch_interrupt_flag
    MOV     r0, #1
    STR     r0, [r1]

    ; set the PendSV exception priority
    LDR     r0, =NVIC_SYSPRI2
    LDR     r1, =NVIC_PENDSV_PRI
    LDR.W   r2, [r0,#0x00]       ; read
    ORR     r1,r1,r2             ; modify
    STR     r1, [r0]             ; write-back

    ; trigger the PendSV exception (causes context switch)
    LDR     r0, =NVIC_INT_CTRL
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]

    ; restore MSP
    LDR     r0, =SCB_VTOR
    LDR     r0, [r0]
    LDR     r0, [r0]
    MSR     msp, r0

    ; enable interrupts at processor level
    CPSIE   F
    CPSIE   I

    ; never reach here!
    ENDP

二、代码实现解释

2.1  函数定义与声明

;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to PROC   ;PROC定义子程序,与ENDP成对使用,表示子程序结束
EXPORT rt_hw_context_switch_to ;导出rt_hw_context_switch_to,让其具有全局属性,可以在C文件调用

该函数输入参数的是线程结构体to_thread的栈指针(sp),进入该函数,该栈指针自动赋值给CPU的r0寄存器。

2.2  获取要切换到的线程的sp指针

; r0的值是一个指针,该指针指向to线程的线程控制块的SP成员
LDR r1, =rt_interrupt_to_thread    ;将 rt_interrupt_to_thread 的地址(不是其本身的值)加载到 r1
STR r0, [r1]                       ;将 r0 的值存储到 rt_interrupt_to_thread 


; 设置 rt_interrupt_from_thread 的值为 0,表示启动第一次线程切换
LDR r1, =rt_interrupt_from_thread  ;将 rt_interrupt_from_thread 的地址加载到 r1
MOV r0, #0x0                       ;配置 r0 等于 0(意味着该线程不存在)
STR r0, [r1]                       ;将 r0 的值存储到 rt_interrupt_from_thread

rt_interrupt_from_thread和rt_interrupt_to_thread是一个32位的全局变量(初始值都为0),用于作为保存相应线程指针的容器。

2.3  设置中断标志位为1

;设置标志为1,表示需要切换,这个变量将在PendSV异常处理函数里切换时被清零
LDR r1, =rt_thread_switch_interrupt_flag   ;将rt_thread_switch_interrupt_flag的地址加载到r1
MOV r0, #1                                 ;配置 r0 等于 1,相当于使能切换标志
STR r0, [r1]                               ;将 r0的值存储到rt_thread_switch_interrupt_flag

rt_thread_switch_interrupt_flag是一个32位的全局变量(初始值都为0),用于标示是否切换。

2.4   

; 设置PendSV异常优先级为最低优先级
LDR r0, =NVIC_SYSPRI2       ;把system priority register(2)的地址加载到r0 
LDR r1, =NVIC_PENDSV_PRI    ;把PendSV priority value (lowest)的地址加载到r1
LDR.W r2, [r0,#0x00] ; read
ORR r1,r1,r2 ; modify
STR r1, [r0] ; write-back

2.5 

; 触发 PendSV 异常 (产生上下文切换)
    LDR     r0, =NVIC_INT_CTRL
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]

2.6

; 放 弃 芯 片 启 动 到 第 一 次 上 下 文 切 换 之 前 的 栈 内 容, 将 MSP 设 置 启 动 时 的 值
LDR r0, =SCB_VTOR
LDR r0, [r0]
LDR r0, [r0]
MSR msp, r0

2.7

; 使 能 全 局 中 断 和 全 局 异 常, 使 能 之 后 将 进 入 PendSV 异 常 处 理 函 数
CPSIE F
CPSIE I
; 不 会 执 行 到 这 里
END

 

你可能感兴趣的:(RT-Thread学习,rt-thread,实现,移植,讲解,总结)