一、源碼
rt_hw_context_switch_to()沒有來源線程,切換到目標線程,在調度器啓動第一個線程的時候被調用。只使用一次。其執行邏輯流程圖如下所示:
其採用彙編語言來實現,如下所示:
;/*
; * 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