1. 程式人生 > >跟我一起寫作業系統(一)——10分鐘寫個作業系統

跟我一起寫作業系統(一)——10分鐘寫個作業系統

轉載註明出處: http://www.cnblogs.com/lucasysfeng/p/4846119.html

  專案地址:https://github.com/lucasysfeng/lucasOS

 

  想動手,但不知從何入手,是學習一門新知識普遍會遇到的尷尬點。筆者喜歡邊實踐邊學習理論,筆者的寫作思路是:入門的文章要避免講一些高深的理論,而應該先丟擲demo,從研究demo入手,逐步加深demo的難度,從而學習這個過程中涉及到的理論知識。下面就讓我們花10分鐘寫個“作業系統”。

第一節 開發環境


  我們在linux下製作軟盤、編譯核心等,因此需要linux開發環境。如果你用windows, 那麼在windows下安裝VMware, 在VMware中安裝ubuntu虛擬機器,此ubuntu作為開發環境。

  注:筆者的開發環境是windows--VMware--ubuntu14.04.

第二節 計算機啟動過程


  寫作業系統看似是一個複雜的過程,但只要我們將過程分解,完成每一步,那麼完成一個作業系統就是水到渠成的事了。好了,我們就看一下計算機的啟動過程,看作業系統何時被啟動的。

  第一步:讀取BIOS

  按下電源按鈕後,計算機首先讀取一塊ROM晶片,這塊晶片裡的程式是"基本輸入輸出系統"(Basic Input/Output System),即BIOS.

  第二步:硬體自檢 

  BIOS會檢查計算機硬體是否滿足執行條件,如果硬體出現問題,主機板會發出不同含義的蜂鳴,啟動中止。

  第三步:啟動順序

  硬體檢查完成後,BIOS會將控制權交給下一階段的啟動程式,注意,“下一階段的啟動程式”可能存放在硬碟中,也可能存放在CD/DVD中,或者軟盤中等等,可以設定BIOS選擇從哪個裝置啟動

  第四步:主引導記錄

  BIOS找到了“下一階段的啟動程式”所在裝置,會讀取該裝置的第一個扇區,即讀取最前面的512位元組,稱為主引導記錄。主引導記錄會告訴計算機下一步到哪裡去找作業系統。

  第五步:bootloader

  計算機讀取"主引導記錄"前面446位元組的機器碼之後,執行事先安裝的“啟動管理器”bootloader,由使用者選擇啟動哪個作業系統。如果你安裝了多個作業系統,那麼就要從這步做出選擇了。

  第六步:載入核心

  好了,選擇作業系統(核心)後,會載入核心,下面就交給核心去處理了。

第三節 主引導記錄


   我們使用虛擬機器來啟動作業系統,上面的第一步和第二步我們不做,由虛擬機器去完成;第三步“啟動順序”我們選擇從軟盤啟動(我們用映象代替,並不是真的軟盤),需要對虛擬機器做下設定,選擇從軟盤啟動。下面重點來看第四步,我們寫一下“主引導記錄”,讓BIOS讀取我們寫的主引導記錄。

   1. 主引導記錄程式碼

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; 檔名 boot.asm   org 7c00h                     ; BIOS讀入MBR後,從0x7c00h處開始執行   ; 下面部分和10h有關中斷,10h中斷用來顯示字元 mov ax, cs mov es, ax mov ax, msg mov bp, ax                    ; ES:BP表示顯示字串的地址 mov cx, msgLen                ; CX存字元長度 mov ax, 1301h                 ; AH=13h表示向TTY顯示字元,AL=01h表示顯示方式(字串是否包含顯示屬性,01h表示不包含) mov bx, 000fh                 ; BH=00h表示頁號,BL=0fh表示顏色 mov dl, 0                     ; 列 int  10h    msg: db  "hello world, welcome to OS!" msgLen: equ $ - msg           ; 字串長度 times 510 - ($ - $$) db 0     ; 填充剩餘部分 dw 0aa55h                     ; 魔數,必須有這兩個位元組BIOS才確認是MBR

  2. 編譯

# nasm boot.asm -o boot.bin

      如果沒有nasm,安裝它 sudo apt-get install nasm, 執行完上述命令,會生成boot.bin檔案,這就是我們的主引導記錄二進位制。

 

第四節 程式碼解釋


   我們再來看下主引導記錄的彙編程式碼,熟悉彙編的讀者可忽略本節。

  1. 為什麼MBR要從0x7c00h處開始執行?

  ORG是偽指令,org 7c00h是告訴編譯器,下面程式碼裝入到記憶體的起始地址0x7c00h處。為什麼呢,這是因為BIOS讀取主引導記錄後,會從0x7c00h處開始執行,那麼BIOS為什麼會從0x7c00h這個地址開始執行,而不是其他地址呢,這一切都要從大明湖畔的8086cpu說起。

  時光飛逝,容顏易老,8086卻還是那個樣子,如圖所示:

圖 8086實物圖

圖 8086引腳圖

  正如圖中所示,8086cpu的地址匯流排寬度為20(AD0-AD19),可以傳送220的地址資訊,即可以定位220(1M)的記憶體地址空間,那麼這1M的記憶體地址空間是如何分配的呢,見下圖所示(圖是386的,我們目前只關心真實模式即1M記憶體地址空間分配):

圖 真實模式記憶體地址空間分佈

  看到0x7c00h了嗎?0x0000h--0x7c00h這一段存的是BIOS中斷向量和一些BIOS資料等,至於到底為什麼以0x7c00h為界,本文不做討論,有興趣看這裡http://www.glamenv-septzen.net/en/view/6。

    2. int 10h是幹嘛的?

當出現int 10h中斷時,表示要操作顯示器了,此時AH暫存器表示如何顯示,程式碼中的AH為13h,表示要在TTY(偽終端)顯示字元,此時其他幾個暫存器都有一定的含義,如下所示:

ES:BP -- 顯示字串的地址    CX -- 顯示字串的長度

BH -- 頁碼                          BL -- 屬性(若AL=00H或 01H)

DH -- 行              DL -- 列

AL -- 顯示輸出方式

下面一段程式碼也就不難理解了:

1 2 3 4 5 6 7 8 9 mov ax, cs mov es, ax mov ax, msg mov bp, ax                    ; ES:BP表示顯示字串的地址 mov cx, msgLen                ; CX存字元長度 mov ax, 1301h                 ; AH=13h表示向TTY顯示字元,AL=01h表示顯示方式(字串是否包含顯示屬性,01h表示不包含) mov bx, 000fh                 ; BH=00h表示頁號,BL=0fh表示顏色 mov dl, 0                     ; 列 int  10h

  3. $和$$是什麼意思?

$   是當前位置
$$ 是段開始位置

下面兩句就不難理解了:

1 2 msgLen: equ $ - msg           ; 字串長度 times 510 - ($ - $$) db 0     ; 填充剩餘部分

  4. 為什麼要有0xaa55h魔數?

  BIOS檢查完硬體後,會尋找下一個裝置來啟動計算機,BIOS找到一個裝置後,會讀取該裝置的第一個扇區,也就是讀取最前面的512個位元組。如果這512個位元組的最後兩個位元組是0x55和0xAA,表明這個裝置可以用於啟動;如果不是,表明裝置不能用於啟動,控制權於是被轉交給"啟動順序"中的下一個裝置。

 

第五節 製作軟盤映象,加入主引導記錄  


  如何用dd命令製作軟盤,自行google之。

  1. 首先,我們製作一個空的軟盤映象empty.img:  

# dd if=/dev/zero of=empty.img bs=512 count=2880

  2. 之後,我們製作一個包含主引導記錄boot.bin的映象檔案lucasOS.img:

# dd if=boot.bin of=lucasOS.img bs=512 count=1

  3. 然後,將empty.img中1個扇區後的資料拷貝到lucasOS.img的後:

# dd if=empty.img of=lucasOS.img skip=1 seek=1 bs=512 count=2879

  這樣就做成了一個大小為1.44Mb的包含主引導記錄的軟盤映象檔案lucasOS.img。

  4. 將虛擬機器ubuntu中的檔案lucasOS.img拷貝到windows下(滑鼠直接拖拽,如果不行google之)。

 

第六節 用軟盤映象lucasOS.img啟動一個空的虛擬機器


 1. VMware建立空的虛擬機器,去掉開機從CD/DVD啟動選項。  

  2. 網路選擇host-only模式。

  3. 選擇從軟盤驅動,路徑選擇上一節已經拷貝到windows下的映象lucasOS.img.

  4. 開啟虛擬機器電源,看到如下畫面,恭喜你,成功了。

  好了,至此,我們完成了主引導記錄,後續會討論載入核心,並進一步討論程序管理、記憶體管理、檔案系統和中斷等等。

 

程式碼獲取


  本系列GitHub地址 https://github.com/lucasysfeng/lucasOS.git

  獲取程式碼:

# git clone https://github.com/lucasysfeng/lucasOS.git

  本講的程式碼是code/chapter1,筆者已經將上面的命令整合到Makefile中了,讀者只需進入目錄,按ReadMe.txt執行即可。有問題請留言