1. 程式人生 > 實用技巧 >作業系統開發:BIOS/MBR 引導

作業系統開發:BIOS/MBR 引導

該系列文章是在學習《作業系統真相還原》時通過自己的話加以理解總結的筆記,首先,致敬作者-鄭剛!在讀本書時不得不佩服,作者底層功力的深厚,不愧是北大的學子,其講解的也通俗易懂,十分詳細,我會努力把它學好,學精,並加以改進,做出一款自己DIY的作業系統。


BIOS 軟體接力第一棒

BIOS 基本輸入輸出系統,BIOS程式碼所做的工作是一成不變的,所以他是被固化到ROM中的一塊只讀區域中,在開機時此ROM會被對映到低端1MB記憶體的頂部,原因是系統在開啟時預設是實地址模式(該模式最大定址範圍0-fffff),所以其定址範圍也就被限制在了0xF0000-x0xFFFFF區域中,這64KB的記憶體就是BIOS的執行程式碼.

在開機的一瞬間,CPU的CS:IP暫存器會被強制初始化為0xF000:0xFFF0,在實地址模式下該地址需要乘以16也就是左移四位加上偏移地址得到,於是0xF000:0xFFF0就等效於0xFFFF0此處的地址距離0xFFFFF只有16個位元組的空間,裡面存放著一條jmp far f000:e05b = fe05b的彙編指令,該指令將跳轉到真正的BIOS開始的位置.

接著BIOS將會通過自身的程式碼對硬體進行自檢測,在初始化硬體後,則開始向記憶體0x000-0x3ff中初始化資料結構以及拷貝中斷向量表,緊接著BIOS將會通過呼叫int 19h中斷,此中斷用以檢測計算機中的硬碟,如果檢測到0盤0道1扇區末尾的兩個位元組是0x55,0xaa則認為此扇區確實存在,於是就會將此區域中的內容,載入到記憶體7c00的位置,並通過一條jmp far 0:0x7c00h

的指令跳轉到該位置執行,這樣BIOS就將CPU控制權交給了MBR了,而BIOS將會再次睡去.

MBR 收到跳轉來源,繼續執行。

此處的7c000就是MBR程式碼的開始位置,之所以是7C00是因為,DOS中要求最小記憶體是32KB,而MBR大小必須是512位元組(1KB),所以選擇32kB中的最後1KB的位置最為合適,32KB(0x8000)-1KB(0x400)=>0x7c00,這就是7C00的由來,同時還需要保證第510-511位元組必須為0x55,0xaa才可以.

儲存以下彙編程式碼,並使用 nasm -o mbr.bin mbr.asm編譯簡易版MBR檔案.

SECTION MBR vstart=0x7c00     ; 告訴編譯器載入到7c00記憶體處
	mov ax,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov fs,ax
	mov sp,0x7c00

	mov ax,Message
	mov bp,ax         ; 儲存字串地址
	mov cx,15         ; 儲存字串長度
	mov ax,01301h     ; 子功能號13是顯示字元及屬性
	mov bx,000ch      ; 頁號位0,使用黑色為背景色,紅色為字型顏色
	mov dl,0
	int 10h           ; 10h中斷,用來顯示字元
	ret

Message: db "hello lyshark !"
times 510-($-$$) db 0  ; 填充510位元組為0
db 0x55,0xaa           ; mbr的結束標誌

進入Bochs目錄下執行bximage.exe生成一個映像檔案,預設是a.img,並將編譯好的mbr.bin寫入到映象中

dd if=mbr.bin of=a.img bs=512 count=1 conv=notrunc

在Bochs目錄下新建並編輯bosh.src儲存,然後執行bochs.exe -f bosh.src模擬執行MBR程式碼.

megs:32
romimage:file=$BXSHARE/BIOS-bochs-latest
vgaromimage:file=$BXSHARE/VGABIOS-lgpl-latest
floppya:1_44=a.img,status=inserted
boot:floppy
log:bochsout.txt
mouse:enabled=0
keyboard: keymap=$BXSHARE/keymaps/x11-pc-de.map

上方螢幕會比較混亂,這裡我們先來進行清屏操作,清屏中斷呼叫也是int10

SECTION MBR vstart=0x7c00     ; 告訴編譯器載入到7c00記憶體處
        mov ax,cs
        mov ds,ax
        mov es,ax
        mov ss,ax
        mov fs,ax
        mov sp,0x7c00

        mov ax,0x600      ; 清屏範圍,也就是寬度
        mov bx,0x0
        mov cx,0x0        ; 清屏 左上角(0,0)
        mov dx,0x184f     ; 清屏 右下角(80=0x4f,25=0x18)
        int 0x10
        mov ax,Message
        mov bp,ax         ; 儲存字串地址
        mov cx,15         ; 儲存字串長度
        mov ax,01301h     ; 子功能號13是顯示字元及屬性
        mov bx,000ch      ; 頁號位0,使用黑色為背景色,紅色為字型顏色
        mov dl,0
        int 10h           ; 呼叫10h號中斷,用來顯示字元
        ret

Message: db "hello lyshark !"
times 510-($-$$) db 0  ; 填充510位元組為0
db 0x55,0xaa           ; mbr的結束標誌

執行結果,如下,但是,列印字串,在底部,因為游標在底部。

設定游標到頂部,這裡百度一下游標中斷,發現了。

接著改進程式碼

SECTION MBR vstart=0x7c00     ; 告訴編譯器載入到7c00記憶體處
        mov ax,cs
        mov ds,ax
        mov es,ax
        mov ss,ax
        mov fs,ax
        mov sp,0x7c00

        mov ax,0x600      ; 清屏範圍,也就是寬度
        mov bx,0x0
        mov cx,0x0        ; 清屏 左上角(0,0)
        mov dx,0x184f     ; 清屏 右下角(80=0x4f,25=0x18)
        int 0x10
        mov dh,0x0        ; 設定游標列號
        mov dl,0x0        ; 設定游標行號
        mov bh,0x0        ; 頁碼
        int 0x10
        mov ax,Message
        mov bp,ax         ; 儲存字串地址
        mov cx,15         ; 儲存字串長度
        mov ax,01301h     ; 子功能號13是顯示字元及屬性
        mov bx,000ch      ; 頁號位0,使用黑色為背景色,紅色為字型顏色
        mov dl,0
        int 10h           ; 呼叫10h號中斷,用來顯示字元
        ret

Message: db "hello lyshark !"
times 510-($-$$) db 0  ; 填充剩餘的510位元組的空間為0
db 0x55,0xaa           ; mbr的結束標誌

完美結果。



讓我們對顯示卡說點什麼?

上面我們通過呼叫BIOS提供的int 0x10中斷來實現列印字元操作,但我們在後期必須要藉助顯示卡來輸出影象,而顯示卡是外部裝置,必須通過匯流排來操作。

由於CPU使用的訊號是TTL電平,而外部裝置都是機械裝置,故他們不會使用該電平驅動,這就導致CPU與硬體裝置沒有辦法實現溝通,硬體工程師們提供的方法是,在這兩者之間架起一座橋,也就是在CPU和外設之間加上一層IO介面,該介面的作用就是實現CPU和外設之間相互做協調轉換。

其次外部裝置的種類也是多種多樣的,其輸出的訊號可能是數字訊號,也可能是模擬訊號,而我們的CPU只能處理數字訊號,數字訊號需要經過數模轉換器<D/A>成模擬量才能送到外設來驅動硬體工作,模擬量也同樣需要經過模數轉換器<A/D>轉換成數字量才能被CPU直接處理,所以介面電路中需要包括A/D轉換器和D/A轉換器。

由於CPU使用的訊號是TTL電平,而外部裝置都是機械裝置,故他們不會使用該電平驅動,這就導致CPU與硬體裝置沒有辦法實現溝通,硬體工程師們提供的方法是,在這兩者之間架起一座橋,也就是在CPU和外設之間加上一層IO介面,該介面的作用就是實現CPU和外設之間相互做協調轉換。

其次外部裝置的種類也是多種多樣的,其輸出的訊號可能是數字訊號,也可能是模擬訊號,而我們的CPU只能處理數字訊號,數字訊號需要經過數模轉換器<D/A>成模擬量才能送到外設來驅動硬體工作,模擬量也同樣需要經過模數轉換器<A/D>轉換成數字量才能被CPU直接處理,所以介面電路中需要包括A/D轉換器和D/A轉換器。

SECTION MBR vstart=0x7c00     ; 告訴編譯器載入到7c00記憶體處
        mov ax,cs
        mov sp,0x7c00
        mov ax,0xb800
        mov gs,ax

        mov ax,0x600      ; 清屏範圍,也就是寬度
        mov bx,0x0
        mov cx,0x0        ; 清屏 左上角(0,0)
        mov dx,0x184f     ; 清屏 右下角(80=0x4f,25=0x18)
        int 0x10

        mov dh,0x0        ; 設定游標列號
        mov dl,0x0        ; 設定游標行號
        mov bh,0x0        ; 頁碼
        int 0x10

        mov byte [gs:0x00],'M'
        mov byte [gs:0x01],0xa4 ; 顯示A=綠色閃爍 4=紅色

        mov byte [gs:0x02],'B'
        mov byte [gs:0x03],0xa5

        mov byte [gs:0x04],'R'
        mov byte [gs:0x05],0xa6
        ret

times 510-($-$$) db 0  ; 填充剩餘的510位元組的空間為0
db 0x55,0xaa           ; mbr的結束標誌