自由軟件社區是一個充滿自由和夢想的地方
在
余年的時間裡它創造了一個又一個奇跡
然而
這些奇跡的創造者不只是Stallman
也不只是Linus Torvalds
而是活躍在世界各地的不計其數的開發人員
在使用各種功能強大的自由軟件時
我總會對其開發者充滿崇敬之情
期盼有朝一日自己也能成為他們中的一員
很多對自由社區充滿向往之情的人
雖然也想努力融身於其中
但又不知該怎麼做
那麼
就請與我們一起從編寫一個簡單的操作系統開始吧!
我們要做的事情
有人可能擔心自己既沒有學過計算機原理
也沒有學過操作系統原理
更不懂匯編語言
對C語言也一知半解
能寫操作系統嗎?答案是沒問題
我將帶大家一步一步完成自己的操作系統
當然如果學一學上述內容再好不過
首先要明確處理器(也就是CPU)控制著計算機
對PC而言
啟動的時候
CPU都處在實模式狀態
相當於只是一個Intel
處理器
也就是說
即使你現在擁有一個奔騰處理器
它的功能也只能是
級別
從這一點上來講
可以使用一些軟件把處理器轉換到著名的保護模式
只有這樣
我們才可以充分利用處理器的強大功能
編寫操作系統開始是對BIOS控制
取出存儲在ROM裡的程序
BIOS是用來執行POST(Power On Self Test
自檢)的
自檢是檢查計算機的完整性(比如外設是否工作正常
鍵盤是否連接等)
這一切完成以後
你就會聽到PC喇叭發出一聲清脆的響聲
如果一切正常
BIOS就會選擇一個啟動設備
並且讀取該設備的第一扇區(即啟動扇區)
然後控制過程就會轉移到指定位置
啟動設備可能是一個軟盤
光盤
硬盤
或者其它所選擇的設備
在此我們把軟盤作為啟動設備
如果我們已經在軟盤的啟動扇區裡寫了一些代碼
這時它就被執行
因此
我們的目的很明確
就是往軟盤的啟動扇區寫一些程序
首先使用
匯編來寫一個小程序
然後將其拷貝至軟盤的啟動扇區
為了實現拷貝
要寫一個C程序
最後
使用軟盤啟動計算機
需要的工具
● as
這是一個匯編程序
它負責把寫的代碼轉換成目標文件
● ld
這是一個連接器
as
產生的目標代碼由它來轉換成真正的機器語言
機器語言是
能夠解讀的形式
● GCC
著名的C編程器
因為我們需要寫一個C程序將自己的OS轉移到軟盤中
● 一張空軟盤
它用於存儲編寫的操作系統
也是啟動設備
● 一台裝有Linux的計算機
這台機器可以很舊
都可以
在大部分標准Linux發行版中都會帶有as
和ld
在我使用的Red Hat
中就包含有這兩個工具
並且在默認的情況下
它已經安裝在機器裡
如果使用的Linux沒有這兩個工具
可以從網上下載(~mayday/)
這兩個工具都包含在一個名為bin
的軟件包中
此外
有關的文檔也可以在網上獲得(/docs/ldp/howto/Assembly
HOWTO/l)
開始工作
使用一個你喜歡的編輯器輸入以下內容
entry start
start:
mov ax
#
xb
mov es
ax
seg es
mov [
]
#
x
seg es
mov [
]
#
x
f
loop
: jmp loop
這是as
可以讀懂的一段匯編程序
第一個句子指明了程序的入口點
聲明整個過程從start處開始
第二行指明了start的位置
說明整個程序要從start處開始執行
xb
是顯存的開始地址
#表明其後是一個立即數
執行語句
mov ax
#oxb
ax寄存器的值就變為
xb
這就是顯存的地址
下面再將這個值移至es寄存器
es是附加段寄存器
請記住
有一個分段的體系結構
它的各段寄存器為代碼段
數據段
堆棧段和附加段
對應的寄存器名稱分別為cs
ds
ss和es
事實上
我們把顯存地址送入了附加段
因此
任何送入附加段的東西都會被送到顯存中
要在屏幕上顯示字符
就需要向顯存中寫兩個字節
前一個是所要顯示字符的ASCⅡ值
第二個字節表示該字符的屬性
屬性包括字符的前景色
背景色及是否閃爍等等
seg es指明下一個將要執行的指令是指向es段的
所以
我們把值
x
(在ASCⅡ中表示的字符是A)送到顯存的第一個字節中
接下來要把字符的屬性送到下一個字節當中
在此輸入的是
x
f
該屬性指的是在藍色背景下顯示白色的字符
因此
如果執行這個程序
就可以在屏幕上得到顯示在藍底上的一個白色的A
接著是一個循環
因為在執行完顯示字符的任務後
要麼讓程序結束
要麼使用一個循環使其永遠運行下去
把該文件命名為boot
s
然後存盤
此處顯存的概念說得不是很清楚
有必要進一步解釋一下
假設屏幕由
列×
行組成
那麼第一行就需要
字節
其中一個字節用於表示字符
另外一個字節用於表示字符的屬性
如果要在第三行顯示某一字符的話
就要跳過顯存的第
和
字節(它們是用於顯示第
列的)
第
和
字節(它們是用於顯示第
列的)
然後把需要顯示字符的ASCⅡ碼值入第
字節
把字符的屬性寫入第
字節
把程序寫至啟動扇區
下面寫一個C程序
把我的操作系統寫入軟盤第一扇區
程序內容如下
#include <sys/types
h> /* unistd
h 需要這個文件 */
#include /* 包含有read和write函數 */
#include
int main()
{
char boot_buf[];
int floppy_desc file_desc;
file_desc = open(/boot O_RDONLY);
read(file_desc boot_buf );
close(file_desc);
boot_buf[] = x;
boot_buf[] = xaa;
floppy_desc = open(/dev/fd O_RDWR);
lseek(floppy_desc SEEK_CUR);
write(floppy_desc boot_buf );
close(floppy_desc);
}
首先以只讀模式打開boot文件然後在打開文件時把文件描述符復制到file_desc變量中從文件中讀取個字符或者讀取直到文件結束在本例中由於文件很小所以是讀取至文件結束然後關閉文件
最後行代碼打開軟盤驅動設備(一般來說是/dev/fd)使用lseek找到文件開始處然後從緩沖中向軟盤寫個字節
在readwriteopen和lseek的幫助頁中可以看到與函數所有有關的參數及其使用方法程序中有兩行比較難懂
boot_buf[] = x;
boot_buf[] = xaa;
該信息是用於BIOS的如果它識別出該設備是一個可啟動的設備那麼在第和的位置該值就應該是x和xaa程序會把文件boot讀至名為boot_buf的緩沖中它要求改變第和第字節然後把boot_buf寫至軟盤之上如果執行代碼軟盤上的前字節就包含了啟動代碼最後把文件存為writec
編譯運行
使用下面的命令把文件變為可執行文件
as boots o booto
ld d booto o boot
cc writec o write
首先將boots文件編譯成目標文件booto然後將該文件連接成最終的boot文件最後C程序編譯成可執行的write文件
插入一個空白軟盤運行以下程序
/write
重新啟動電腦進行BIOS的界面設置並且把軟盤設為第一個啟動的設備然後插入軟盤電腦從軟盤上啟動
啟動完成後在屏幕上可以看到一個字母A(藍底白字)啟動速度很快幾乎是在瞬間完成這就意味著系統已經從我們制作的軟盤上啟動了並且執行了剛才寫入啟動扇區的程序現在它正處在一個無限循環的狀態所以如果想進入Linux必需拿掉軟盤並且重啟機器
至此這個操作系統就算完成了雖然它沒有實現什麼功能但是它已經可以啟動機器了
下一期我將在這個啟動扇區程序裡加入一些代碼使它可以做一些比較復雜的事情(比如使用BIOS中斷保護模式切換等等)
From:http://tw.wingwit.com/Article/program/Oracle/201311/18813.html