今天聊下移植RTOS時RISC-V內核時單片機任務棧保存哪些內容。
上一章中列舉了所有的寄存器,當需要切換任務時刻的寄存器值,除x0恒為0,其他的寄存器無法預知其值,切換時均需要保存(gp寄存器編譯好后,固定不變,理論上可以不操作,為保持一致性和完整性,一并保存),如果使用浮點,還應該包括浮點寄存器。 每個RTOS均會定義一個和上下文保存相關的結構體,以rt-thread為例,可以看到如下圖1的數據結構定義。
圖1 上下文保存結構體
可以看到除了通用寄存器外,還有兩個前文提到的成員mepc、mstatus,其中mstatus中含有中斷的使能控制位,而mepc為機器模式下異常程序指針寄存器,其值會在執行mret后更新給pc,我們正式通過設置該寄存器的值來控制程序運行的切換。
當我們新建一個線程,初始化線程時,會為其開辟一個線程棧(程序中通常設置一個數組),即對上述結構體做初始化,在rt-thread中的代碼如下圖2所示。
圖2 線程堆棧初始化
由程序可知,堆棧初始化在線程初始化中被調用,線程初始化程序中首先將整個堆棧空間設成“#”,然后根據堆棧的增長方向設置不同參數,以紅框中的向下增長為例,將線程的入口位置,線程可以帶一個參數,返回地址,堆棧頂部地址。從堆棧初始化程序*rt_hw_stack_init中可以看出,其先將堆棧頂部地址對齊,然后向下偏移一個rt_hw_stack_frame結構體的大小,用于存儲圖1中需要存儲的寄存器,并對該部分空間進行了初始化。其中把線程的入口地址給了mepc,線程輸入參數給a0,mstatus初始值(MPP、MPIE、FS、MIE),即強制機器模式,使能浮點,MPIE為1,MIE為0。如果不帶硬件浮點,可將該值設置為0x1880。另外設置ra為線程的返回地址,一般情況下一個線程我們希望一直運行的,當需要返回時說明該線程不再需要運行,所以返回地址一般是一段將該線程從線程列表中刪除并切換至下一個線程的一段程序,即圖2紅框的中調用的函數_rt_thread_exit。
初始化線程時會定義一個rt_thread結構的全局變量,線程的操作即依靠該結構體。其內部內容如下圖3所示,其內部可以看到一個sp成員,初始化好的堆棧指針即傳給該成員。
圖3 rt_thread結構體詳情
綜上可以看出有每個線程一個rt_thread結構體,由rt_thread->sp可獲得該線程的堆棧位置,堆棧的棧頂的sizeof(rt_hw_stack_frame)空間存放了該線程運行需要的CPU寄存器值,剩余空間用于該線程運行時變量的出入棧。
以上的內容在其他RTOS中也能看到,例如上下文保存結構體rt_hw_stack_frame在華為鴻蒙LiteOS_M中有TaskContext,TencentOS_Tiny中有cpu_context_t,而線程管理的結構體rt_thread,LiteOS_M中LosTaskCB,TencentOS_Tiny中有k_task_st等。
-
單片機
+關注
關注
6043文章
44617瀏覽量
638194 -
寄存器
+關注
關注
31文章
5363瀏覽量
121083 -
內核
+關注
關注
3文章
1382瀏覽量
40405 -
RTOS
+關注
關注
22文章
819瀏覽量
119870 -
RISC-V
+關注
關注
45文章
2322瀏覽量
46528
發布評論請先 登錄
相關推薦
評論