基於ARM的自制最小操作系統Open-OS:源起

嵌入式軟件開發是一種軟硬件結合非常緊密的職業,門檻較高,需要掌握的知識點較廣(軟件和硬件相關都要學習),彙編、C語言、編譯相關、計算機硬件相關、操作系統原理、數字電路相關、驅動相關等等。

而學習過程中最困難的當屬操作系統和處理器相關。不管是流行的linux操作系統還是ARM微處理器,源碼和數據手冊都是以千計、萬計,體量太大,學習起來容易迷失在這個“大森林”裡,也容易望而生畏,導致失去興趣。對此,很多初學者或者單片機轉linux的開發人員應該是深有體會。可能很多讀者學習linux kernel一上來就從_strart_kernel_函數開始,細節越展開發現需要的知識點越多,最後自己也不知道該從那裡學起。同樣我也深有感觸,學習嵌入式相關以及操作系統一定要有個整體認識,然後再深入細節。因此想寫些相關的技術文章,一是對過去自己知識的總結和回顧,二來也希望能夠幫助到正在學習的嵌入式的朋友。

ARM Open OS

為了能夠讓讀者有一個更好的學習體驗,幫助讀者理解操作系統的一些基本概念和實現原理,特別的針對ARM處理器設計了一個最小的簡單的操作系統Open OS。在介紹ARM Open OS之前,本文將介紹一些基本的概念,為後續OS的編寫打下基礎。

ARM處理器基礎

計算機的一般模型

在進行嵌入式編程之前,首先就要清楚的認識處理器的一般模型,需要從程序員編程的角度去理解。一般的處理器模型(存儲程序計算機)如圖1所示:

基於ARM的自制最小操作系統Open-OS:源起

圖1 存儲程序計算機模型

中央處理器或者常說的CPU是通過寄存器來運行程序和處理數據的,不同的處理器所包含的寄存器的數量和名字都是不一樣的,但是CPU的寄存器的功能基本都是一致的,因此CPU寄存器的值基本就決定了CPU的行為。例如CPU的內部有個寄存器PC程序計數器,PC寄存器的值就決定了程序的走向(CPU根據PC寄存器的值來取指令,程序狀態寄存器決定了指令的相關跳轉等等)。

上述可以得出一個很重要的結論,相關寄存器的值代表了當前時刻CPU的行為

ARM處理器模型

ARM處理器內核如圖2所示,箭頭代表了數據的流向,上下兩邊的直線代表了總線。

基於ARM的自制最小操作系統Open-OS:源起

圖2 ARM內核結構

  1. 圖中有兩條總線,Data和Address。數據通過Data總線進入到寄存器(這裡的數據包含了指令和數據)。數據和指令共享一條Data總線(馮.渃伊曼結構)。
  2. 對於存儲器(內存)訪問,只有load、store、swap指令可以對存儲器中的數據進行訪問。Load指令從存儲器複製數據到CPU寄存器。Store指令從CPU寄存器複製數據到存儲器。沒有直接操作存儲器中的數據的指令,數據的處理只能在CPU的寄存器中進行。

ARM流水線

ARM處理器使用流水線來增加處理器指令執行的速度,不管是3級流水線還是5級流水線、13級流水線。再複雜的指令的流水線都包含了下面3個階段執行。


  • 取指
  • 譯碼
  • 執行

3階段流水線如圖3所示。

基於ARM的自制最小操作系統Open-OS:源起

圖3 指令流水線

這裡需要重點指出的是:程序計數器(PC)指向被取的指令,而不是指向正在執行的指令。也就是說:PC=當前指令的執行地址+8。這個是ARM所有流水線的結構特徵。

CPU正常的操作過程中,在執行一條指令的同時,對下一條指令進行譯碼,並將第三條指令從存儲器中取出。

說明:PC的值非常重要,在異常切換時常常需要通過PC來計算返回地址。

ARM處理器有兩種操作狀態:

ARM狀態和Thumb狀態,這兩種狀態的PC值計算存在區別,後續我們都是圍繞ARM狀態來學習。

ARM彙編語言基礎

本節僅描述gcc內聯彙編的基本語法,具體的ARM指令讀者可參考其他相關的資料。

GCC內聯彙編的一般格式:

asm volatile(

彙編語句

: 輸出運算符列表

: 輸入運算符列表

: 被更改資源列表

);

volatile:可選

舉例:

int main(void){

unsigned int sp=0,ip=0;

asm volatile(

"mov sp,%0\\n\\t"

"mov pc,%1\\n\\t"

:

:"r" (sp),"r" (ip)

);

return 0;

}

上面的代碼中第一條mov指令,該指令將%0賦值給sp。這裡符號%0代表出現在輸入運算符列表和輸出運算符列表中的第一個值。%1代表出現在列表中的第二個值,依此類推。所以,在該段代碼中,%0代表的就是“r”(sp)這個表達式的值了。

“r”(sp)這個表達式中,sp代表的正是C語言向內聯彙編輸入的變量,操作符“r”則代表sp的值會通過某一個寄存器來傳遞。在GCC中與之相類似的操作符還包括“m”、“I”,等等,其含義見下表:

基於ARM的自制最小操作系統Open-OS:源起

表:內聯彙編操作符

多任務機制

Windows任務管理器

現實生活中使用電腦,我們能夠做到可以一邊視頻網站看視頻,同時一邊可以通過社交軟件和網友聊天,是因為windows操作系統支持多任務機制。在windows的任務管理器下可以看到多個任務的列表。

基於ARM的自制最小操作系統Open-OS:源起

圖4 windows任務管理器

那麼如何簡單的理解多任務機制呢?

假設你是僱主,家裡只有一個保姆(CPU),那麼保姆上班時間幹些什麼將由你來決定。現在需要給保姆安排兩個任務:客廳打掃衛生和廚房洗菜。可按照下圖5來安排。

基於ARM的自制最小操作系統Open-OS:源起

圖5 多任務機制演示

在圖5中,首先將保姆的上班時間(假設是8個小時)分成等長小段時間,然後按照時間長度輪流執行安排的兩個任務(打掃衛生和洗菜)。只要這個保姆做事的速度足夠快,切換時間足夠短,你會感覺到這名保姆同時在客廳和廚房裡幹活。這就是宏觀上的並行執行,也就是多任務的運行機制。

在T4時刻,兩項任務都已經完成了,那麼保姆沒事可幹了,就處於空閒狀態,保姆等待僱主重新安排任務。

假設現在需要給這名保姆安排三個任務:客廳打掃衛生和廚房洗菜、洗衣服。多任務機制演示如圖6所示。


基於ARM的自制最小操作系統Open-OS:源起

圖6 三任務演示機制

任務上下文

什麼是任務上下文?

簡單的理解了多任務機制之後,再來看一個關鍵的概念:任務上下文。

要理解任務上下文,首先就要理解什麼是任務?按照上面的例子,任務就是保姆現在正在做的事情(例如正在客廳打掃衛生),是一個動態的概念。

那麼任務上下文就是保姆在客廳打掃衛生過程中某一時刻的狀態,這個狀態就是衛生打掃到那個具體位置數據(例如客廳拖地拖到了一半的位置)。有了這個具體位置的數據,僱主可以隨時的打斷保姆的客廳任務執行或者安排新的任務。當保姆再次執行客廳打掃任務時,只要按照上次的打掃位置記錄繼續執行就可以了。

延伸

任務和進程的關係? 其實某種程序進程就是任務,任務就是進程。進程就是進行中的程序。

<code>linux的進程描述符(task命名)
task_struct{
... ...
}/<code>

處理器的角度

前文提到了一個非常重要的一點:寄存器的值代表了當前時刻CPU的行為

任務可以看作是用戶程序在處理器上的運行,是一個動態的概念。任務上下文可以理解為CPU的“寄存器數據的快照”。任務上下文是和CPU密切相關的概念,不同的處理器有不同的處理器上下文定義。

比如在ARM處理器中,設計多任務操作系統時,會把大部分的硬件寄存器作為任務上下文的內容。ARM處理器的寄存器程序員視圖如圖7所示。

基於ARM的自制最小操作系統Open-OS:源起

圖7 ARM寄存器程序員視圖

寄存器的具體含義這裡就不介紹了,感興趣的讀者可查閱相關的資料。

任務切換

有了任務和任務上下文的概念,那麼任務切換就很好理解了,任務切換其實就是上下文切換。

任務切換的過程

還是以上文保姆的例子來講,假設保姆在執行“客廳打掃衛生”的T1時刻,保姆停止任務執行,同時將當前任務的上下文(也就是客廳打掃衛生的具體位置數據記錄並保存下來),然後保姆進入廚房查看任務“廚房洗菜”的上下文(菜洗到哪裡數據),根據“廚房洗菜”的上下文的內容繼續執行“廚房洗菜”任務。這個過程就叫任務切換。

ARM處理器的角度來看下任務切換的具體過程:

從上文我們知道任務的上下文其實就是寄存器的數據快照。那麼ARM處理器中比較重要的寄存器是PC和SP。PC是當前任務運行的具體位置,SP寄存器表示的棧的指針,當然還有一些其他的重要寄存器,這裡不一一列出。

任務A和任務B的切換

假設系統中有兩個任務A和B;當前的處理器正在運行A任務,那麼此時任務A的上下文情況如圖8所示:

基於ARM的自制最小操作系統Open-OS:源起

圖8 任務A運行時的上下文

這時發生任務切換,那麼首先做的就是保存當前任務A的上下文(寄存器數據快照),將CPU的寄存器內容保存到任務A的棧中,這時任務A的運行情況如圖9所示:

基於ARM的自制最小操作系統Open-OS:源起

圖9 任務A的上下文保存

任務A的上下文保存完成之後,接下來要做的就是將任務B的上下文內容恢復到ARM處理的寄存器中(退棧操作),圖10所示。

基於ARM的自制最小操作系統Open-OS:源起

圖10 任務B的上下文恢復

最後,退棧完成後,ARM CPU開始執行任務B,此時CPU的運行情況入圖11所示。

基於ARM的自制最小操作系統Open-OS:源起

圖11 任務B的上下文情況

最後

到了這一步,相信讀者已經對多任務操作系統有了一個基本的理解了,那麼下一步如何編程去實現呢?

下一步計劃:編寫彙編代碼,使用qemu模擬ARM處理器來實現最簡單的OS。敬請期待!

關於操作系統的一些概念的描述,本文描述的不可能盡善盡美,但是基本已經做到了通俗易懂。如有錯誤或者不妥之處,敬請廣大讀者批評指正。

參考文獻:

ARM System Developer's Guide

ARM彙編程序分析與設計

Ucos操作系統分析


分享到:


相關文章: