2007年9月13日 星期四

PC 作業系統實作馬上入門

Standard
最近在整理過去的許多筆記,看到了很多懷念的東西,尋思當初許多的瓶頸,都缺少一個人幫我打通任督二脈,讓我一路走起來倍感艱辛,雖然不後悔這樣沒章法的強幹式學習,但許多冤枉路我心裡明白是白走了,尤其在作業系統這部份,對大多數人來說,更是不易突破的關卡。因為,看程式方面的書籍它不會教你,看硬體架構的書又不告訴你程式實作,如果想自己融會貫通,又因為沒有良好的入門範例,不知道該注意哪些事項而挫折連連。

開始前,你要有個體認,我們要寫的是作業系統,整台電腦都將由我們的程式完全控制,所以,如果你的程式不正常,將會落得停格當機下場,沒有『程式關閉,請聯絡...』或是『Core...』這套。另外,不要想說有任何 API 可以用,你都要一一自己打造這一切,因為系統開發本來就是一件辛苦的事,你正在開拓一個沙漠的綠洲。

而大多數人在學習作業系統撰寫時,常都會卡在第一步:我要如何讓自己的作業系統啟動?然後如同第一次學寫程式時,出現一行 Hello World?當初的我也在這問題上打轉好一陣子,縱使我會組合語言、有過不少寫程式經驗、看過許許多多的相關書籍,但我還是不知道該從哪開始。


我們先來了解電腦啟動的流程:
  1. 電腦開啟電源,會啟動 ROM 裡面的 BIOS 執行硬體檢查和初始化。
  2. BIOS 會依序搜尋 BIOS 設定中的啟動裝置(Boot Device),如硬碟。
  3. 一旦在某個啟動裝置上發現了啟動磁區(Boot Sector 大小為 512 Bytes),就會將此磁區 512 Bytes 的程式載入到記憶體位址 0000:7c00
  4. BIOS 會跳到記憶體位址 0000:7c00 執行被載入的程式,並將執行權全權交給它。


以下是一個 512 Bytes 的簡單開機程式實作範例﹝組合語言﹞:

org 07c00h ;此程式將被載入到 0000:7c00 執行
mov ax, cs
mov ds, ax
mov es, ax
call Disp ;呼叫 Disp 顯示字串
jmp $ ;無限回圈

Disp:
mov ax, BootMsg
mov bp, ax ;指定 BootMsg 的位址
mov cx, 16 ;BootMsg的字串長度
mov ax, 01310h ;ah=13, al=01h
mov dl, 0
int 10h ;中斷 10h 顯示字串
ret



BootMsg db "Hello, OS World!"
times 510-($-$) db 0 ;將編譯出來的程式填充為 510Bytes
dw 0xaa55 ;填入最後兩個結束字元 55 和 AA
此程式執行結果將會顯示『Hello, OS World!』,然後進入無限迴圈。

這程式編譯出來會是一個 512B 的小程式,你只要將它寫入硬碟或磁碟片的開始 512 磁區,然後用它們開機啟動就可以看到執行結果。如果你在 Linux 環境下,可用 dd 指令來寫入磁區。假若你嫌每次測試都要重新開機很浪費時間,可以另外準備一台電腦或是使用模擬器、虛擬機器程式,如 VMware等。

註:本文是針對 x86 系列的 PC 電腦架構所寫,所以無法在其他如 PPC、Alpha 等架構上實作。