學習作業系統原理最好的方法是自己寫一個簡單的作業系統。
前面鋪墊了這麼久,今天終於開始寫程式了。本講將介紹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