如何?一個最簡單的作業系統 這裡為了簡單,就不考慮可移植性開求,不從BOOT部分來接收參數,也不對硬體進行檢測, 也不需要進行DATA段,程式碼片段的重定位。我只是讀了LINUX核心相關部分,並未自己去實現 一個作業系統,所以我以下所說的只是概念性的東西: 1.接管系統的中斷處理,由於BOOT部分的代碼決定了那個中斷向量表,從而決定了系統中斷 之後進入的記憶體位置,但BOOT並不知道作業系統的中斷處理函數位置所在啊,怎麼辦呢? 有幾種方法,其一是:如果你的板子可以重新對應地址,也就是可以將記憶體條所在的位置 重新對應成0x0開始,那麼在連結核心的時候,就將作業系統自己的中斷向量表定位在0x0處 並且在BOOTLOADER引導結束時就完成映射操作,並讓CPU跳轉到0x0處執行;如果沒有重映 射功能,我就不曉得怎麼辦了,不過我想到一個折衷的辦法,就是在BOOTLOADER啟動完成 時(也就是將CPU控制權交給作業系統核心時),重新改寫FLASH的0x0地區,就是將操作 系統的核心的中斷向量表寫入FLASH區的0x0處,比如,當一個IRQ發生時,CPU決定了會 跳入0x18(假設這裡FLASH佔用地址匯流排0x0至0x0fffffff,記憶體佔用0x20000000至0x2fffffff) ,而BOOTLOADER在最後將0x18處的代碼修改成了0x20000000加上0x18的地址處的代碼,而這個 地址就是核心的中斷向量表中的相關跳轉指令,就相當於跳轉進了核心所關聯的IRQ處理函數 的地址上去執行中斷處理函數了,而這樣的不好之處在於:當系統重新上電之後,BOOT的 中斷向量表已經被修改,除非BOOT本身不使用中斷,呵,在這樣簡單的系統中,BOOT是不 需要中斷功能的 2.這裡為了簡單,所以沒有使用分頁記憶體管理,就不需要建立頁表等操作,直接進行操作 系統的堆棧設定,同BOOT一樣的設定過程一樣,接著就進行BSS段清零操作,這裡的BSS段 是指作業系統自身的BSS段,與BOOT的BSS段是同一個含義只是用在了不同的地方了,接著 就跳入了MAIN函數 3.為了最大可能的簡單,採用靜態建立任務結構數組,比如只建立十個任務,那麼首先要 為這十個任務結構分配段記憶體,可以在堆上分配(這個分配的記憶體直到作業系統結束才會 被釋放,當然也可以指定一片作業系統的其它地方都用不到的記憶體地區,不過這樣寫的話 就有點外行的味道了,而符務結構數組的指標卻是全域變數,存放在BSS段或者DATA段), 由於在上一步中已經分配了一個系統堆棧,那麼我們這十個任務就分享這總體的堆棧地區 這裡的重點就是如果定義每個任務結構數組裡面的結構,可以參照LINUX的相關部分設計 4.中斷處理:在第一步中已經確定了CPU進行相關的幾類型的中斷跳轉地址,而相同類型 的中斷卻只有一個入口地址,這裡的中斷處理就會完成以幾個動作: 其一:入棧操作,包括所有寄存器入棧,至於這個棧,就是在第二步中所設定的IRQ棧, 其二:屏掉所有中斷,呵,這裡為了簡單起見,所以在處理中斷時不允許再次發生中斷 其三:讀取中斷相關的寄存器,判別是發生了什麼中斷,以至於跳進相關的中斷處理函 數中去執行(在這裡只包括兩種中斷,一是時鐘中斷,另一個是SWI中斷,也就是所謂 的系統調用時需要用到的) 其四:等待中斷處理完成,然後就開啟中斷並出棧,恢複現場,將CPU控制權交給被中斷 的代碼處 注意: 其一:在MIAN中必須首先確定整個系統有哪些需要處理的中斷,也就是有哪些中斷處理 函數,然後才編寫這裡的中斷處理函數 其二:本作業系統不處理虛擬記憶體,其至連CPU異常都不處理(一切都為了簡單),一旦 發生異常,系統就死機 5.對TIMER的實現,首先確定時間片,為了讓系統更穩定,而且我們不需要即時功能,盡 可能讓時間片設定長一點,比如我們讓一個任務運行20個時鐘滴答數,然後應根據系統 頻率來確定每個系統滴答所佔用的毫秒,這裡使用5毫秒讓系統定時器中斷一次,那麼就 需要寫時鐘寄存器,具體參閱晶片資料,計算下來,一個任務最大可能連續運行100毫秒 ,注意:我們的作業系統不支援核心搶佔,同時只支援兩級中斷優先順序,就是只有時鐘 中斷的優先順序高一點,其它的優先順序都低一級,但是在中斷處理一節中卻屏掉了這個功能 因為一進入中斷處理,就禁止中斷,所以不管其它中斷優先順序有多高都沒有用的,這樣做 優點是簡單了,但不好之處顯而易見,特別在相關中斷處理函數如果進入了死迴圈,那麼 整個系統就死了,而且時間片也變得不準確了,反正都不用即時,也不需要即時鐘支援嘛 至於中斷優先順序設定請參閱晶片資料 6.進程調度的實現,也就是do_timer函數(時鐘中斷處理函數),有一個全域變數指標, 指向的就是當前任務結構數組(或者鏈表),當時鐘中斷時,就進入此函數中,首先判斷 任務結構體中的時間片是否用完,如未用完,就減一,然後退出中斷,讓CPU繼續運行當 前的任結構,若用完了時間片,就重設時間片,並重新尋找任何結構數組中的下一個等待 啟動並執行任務,若找到了,就切換至新的任務,至於如何切換,請見下一頁描述,如果未找 到就切換到IDLE任務(類似於LINUX,呵呵,所有的處理就是模仿LINUX,由於本人水平太 差,所就不能自創一招),注意:為了簡單,所以沒有實現任務優先順序,也未實現任務 休眠等,也就是說只要靜態地決定了有十個任務,這十個任務就按先後順序一個一個執行 而且每個任務都不允許結束,就是說在每個進程中的最後一句代碼都必須用死迴圈,不然 的話系統就跑飛了),還有一點,進程不支援訊號,沒有休眠與喚醒操作,這個CPU就是 不停地在運行,呵呵,反正CPU又不是人,所以不需要人權的哈!!!這種調度是不是簡 單得不能再簡單了?????!!!! 7.串口不使用中斷,這就是最大可能的降低難度,串口使用論詢的方式來實現讀寫(當 然是阻塞的方式了哦,而且只有寫,不允許讀,因為讀的時候需要涉及到採用中斷方式, 因為輪詢方式有個不好的地方,那就是正在讀的時候,這裡有可能當前進程的時間片用 完了,系統切換到另一個進程,這裡你在PC機的串口輸入的資料就丟棄了,唉,又是為 了簡單嘛) 8,最後一步就是MIAN函數的最後一部分,將本進程當作IDLE進程(相當於修改任務結構 數組中的資料),開啟中斷,將當前進程加入一段死迴圈,以免它退出去。 9.編譯你的BOOTLOADER,KERNEL,並燒寫至FLASH,反覆調試 10.至此將你的at91rm9200(或者是其它相類似的晶片)的串口接上PC機,開啟超級終端, 開啟板子電源,說不定你的作業系統就列印出了"hello,world"了!!!一個最簡單的操作 系統就出來了 下一頁是具體的功能模組實現 |