自己動手從零寫桌面操作系統GrapeOS系列教程——13.向MBR中寫入程序

學習操作系統原理最好的方法是自己寫一個簡單的操作系統。


前面鋪墊了這麼久,今天終於開始寫程序了。本講將介紹3個逐步深入但非常簡單的程序,一方面是讓大家熟悉開發流程,另一方面是順便解決前面遇到的CPU佔用率高的問題。

一、mbr1.asm回顧

mbr1.asm的代碼之前我們介紹過,這裏我們回顧一下代碼和演示步驟。
mbr1.asm代碼如下:

;生成一個空的MBR
times 510 db 0 ;前510個字節全爲0
db 0x55,0xaa   ;最後兩個字節是0x55和0xaa。

下面我們來演示:

1.啓動並登錄CentOS

在VirtualBox中啓動CentOS虛擬機,並用PowerShell登錄到CentOS虛擬機。

2.創建空虛擬硬盤

如果沒有虛擬硬盤或想重新創建一個空的虛擬硬盤,執行下面這條語句:

dd if=/dev/zero of=/media/VMShare/GrapeOS.img bs=1M count=4

截圖如下:

在上面截圖中,用hexdump命令查看生成的虛擬硬盤文件GrapeOS.img,可以看到每個字節都是0,符合預期。

3.彙編mbr1.asm

nasm mbr1.asm -o mbr1.bin

截圖如下:

在上面截圖中,用hexdump命令查看生成的mbr1.bin,共512個字節,前510個字節都是0,最後兩個字節是0x55和0xaa,符合預期。

4.將mbr1.bin寫入到虛擬硬盤中

dd conv=notrunc if=mbr1.bin of=/media/VMShare/GrapeOS.img

截圖如下:

在上面截圖中,我們同樣用hexdump命令驗證,看到的確是將mbr.bin寫入到虛擬硬盤的第一個扇區中了。

5.啓動QEMU

在Windows的cmd命令行中運行如下命令:

qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img

從截圖上可以看到,運行結果和之前的一樣。回顧到此爲止,下面來解決CPU佔用率高的問題。

二、CPU佔用率高的原因

前面我們介紹過,在QEMU+GDB調試中,反編譯16位代碼是有問題的,下面來介紹另一種反編譯方法。nasm彙編器自帶了一個反彙編工具叫ndisasm,下面我們來反彙編mbr1.bin。

ndisasm mbr1.bin

截圖如下:

從截圖中可以看到兩個0字節正好是一條彙編指令“add [bx+si],al”,最後的2個字節0x55和0xaa也正好是指令“push bp”和“stosb”。但這些都不是我們要寫的程序,只是這些二進制數正好是某條機器指令。從BIOS跳轉到0x7c00地址後,無論此處是什麼樣的二進制數,CPU都會把它當作指令一條一條的執行。當執行完這512字節,會繼續執行後面內存中的數據。而後面內存中的數據是不確定的,CPU就會亂執行半天,而且也沒有意義,這就是程序跑飛了。下面我們先來解決程序跑飛的問題。

三、mbr2.asm阻止程序跑飛

1.程序講解

mbr2.asm代碼如下:

jmp $ ;$表示當前行的地址
times 510-($-$$) db 0 ;$$表示段開始的地址,$-$$表示當前行前面的代碼佔用的字節數。
db 0x55,0xaa

在Linux命令行中執行如下命令:

nasm mbr2.asm -o mbr2.bin
hexdump mbr2.bin -C
ndisasm mbr2.bin

從上面截圖中可以看到“jmp $”生成的機器碼是“0xeb,0xfe”,其中0xeb是操作碼,0xfe是操作數。這條指令中的操作數是當作有符號數處理的,0xfe換算成十進制數是“-2”(負2)。而這條指令共2個字節,當CPU讀取完這條指令後寄存器ip的值會加2,執行完這條指令後,寄存器ip的值會加負2。這樣的話CPU就會不斷的重複執行這條指令,程序就不會跑飛了。

2.程序演示

下面我們將mbr2.bin寫入到虛擬硬盤的第一個扇區。

dd conv=notrunc if=mbr2.bin of=/media/VMShare/GrapeOS.img
hexdump /media/VMShare/GrapeOS.img -C

然後用調試模式觀察一下。

qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img -S -s

前面我們介紹過,這裏GDB是按32位反彙編的,16位反彙編是有問題的。但有些彙編代碼在16位和32位下生成的機器碼是一樣的,比如這裏的jmp $。所以這裏的反彙編也可以適當參考一下。從上面截圖上可以看到,每次單步運行後,程序地址仍然停留在0x7c00。這就是通過死循環來防止程序跑飛的辦法。
下面我們來刪除斷點,讓程序正常運行。
首先來查看斷點:

(gdb) i b

刪除斷點:

(gdb) d 斷點編號

然後讓程序繼續運行:

(gdb) c

截圖如下:

mbr2.asm雖然解決了程序跑飛的問題,但CPU佔用率仍然高,筆記本風扇還是呼呼的轉。下面我們來徹底解決這個問題。

四、mbr3.asm徹底解決CPU佔用率高的問題

mbr3.asm的代碼如下:

stop:
hlt ;使CPU暫停運行,直到有中斷髮生。(降低CPU使用率)
jmp stop 

times 510-($-$$) db 0
db 0x55,0xaa

上述代碼主要用了一個hlt指令,讓CPU暫停,如果有中斷髮生,會執行下一行jmp stop,然後又執行hlt。這樣不僅防止了程序跑飛,而且降低了CPU使用率。
有了前面的基礎,我們這次編譯運行一氣呵成。
在Linux命令行中執行:

nasm mbr3.asm -o mbr3.bin
dd conv=notrunc if=mbr3.bin of=/media/VMShare/GrapeOS.img

在Windows命令行中執行:

qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img

截圖如下:

從上圖任務管理器中可以看到,QEMU的CPU佔用率已經降下來了。


本講視頻版地址:https://www.bilibili.com/video/BV1io4y1i7GP/
本教程代碼和資料:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS操作系統QQ羣:643474045

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章