自己動手從零寫桌面操作系統GrapeOS系列教程——21.彙編語言寫硬盤實戰

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


在上一講中我們學習了用匯編語言讀硬盤,本講我們來學習用匯編語言寫硬盤。同樣也是設計一個簡單的實驗,實驗內容爲:

在內存中準備一段有特徵的512字節數據,地址爲0x7e00~0x7fff,其特徵是前3個字節依次爲4、5、6,最後3個字節依次爲6、5、4。然後將該段內存數據寫入到硬盤的第2個扇區,並查看虛擬硬盤第2個扇區的數據是否與內存中0x7e00~0x7fff的數據一致,如果一致則說明寫硬盤成功。

本講代碼文件只有一個boot2.asm
boot2.asm代碼如下:

;定義常量
DISK_BUFFER equ 0x7e00 ;臨時存放數據用的緩存區,放到boot程序之後。0x7e00~0x7fff。

org 0x7c00

;初始化段寄存器
mov ax,cs
mov ds,ax ;ds指向與cs相同的段

mov bx,DISK_BUFFER
;向緩存區前3個字節依次寫入4、5、6。
mov byte [bx+0],4
mov byte [bx+1],5
mov byte [bx+2],6
;向緩存區最後3個字節依次寫入6、5、4。
mov byte [bx+509],6
mov byte [bx+510],5
mov byte [bx+511],4

mov si,DISK_BUFFER
mov edi,1 ;寫入硬盤的第2個扇區
call func_write_one_sector

stop:
hlt
jmp stop 

;將內存中的512個字節寫入到硬盤的一個指定扇區中(主硬盤控制器主盤)
;輸入參數:ds:si,edi。
;ds:si 數據源內存地址
;edi LBA扇區號
;輸出參數:無。
func_write_one_sector:
;第1步:檢查硬盤控制器狀態
mov dx,0x1f7
.not_ready1:
nop ;nop相當於稍息 hlt相當於睡覺
in al,dx ;讀0x1f7端口
and al,0xc0 ;第7位爲1表示硬盤忙,第6位爲1表示硬盤控制器已準備好,正在等待指令。
cmp al,0x40 ;當第7位爲0,且第6位爲1,則進入下一個步。
jne .not_ready1 ;若未準備好,則繼續判斷。
;第2步:設置要寫入的扇區數
mov dx,0x1f2
mov al,1
out dx,al ;寫入1個扇區
;第3步:將LBA地址存入0x1f3~0x1f6
mov eax,edi
;LBA地址7~0位寫入端口0x1f3
mov dx,0x1f3
out dx,al
;LBA地址15~8位寫入端口寫入0x1f4
shr eax,8
mov dx,0x1f4
out dx,al
;LBA地址23~16位寫入端口0x1f5
shr eax,8
mov dx,0x1f5
out dx,al
;第4步:設置device端口
shr eax,8
and al,0x0f ;LBA第24~27位
or al,0xe0 ;設置7~4位爲1110,表示LBA模式,主盤
mov dx,0x1f6
out dx,al
;第5步:向0x1f7端口寫入寫命令0x30
mov dx,0x1f7
mov al,0x30
out dx,al
;第6步:檢測硬盤狀態
.not_ready2:
nop ;nop相當於稍息 hlt相當於睡覺
in al,dx ;讀0x1f7端口
and al,0x88 ;第7位爲1表示硬盤忙,第3位爲1表示硬盤控制器已準備好數據傳輸。
cmp al,0x08 ;當第7位爲0,且第3位爲1,進入下一步。
jne .not_ready2 ;若未準備好,則繼續判斷。
;第7步:向0x1f0端口寫數據
mov cx,256 ;每次寫入2字節,一個扇區需要寫256次。
mov dx,0x1f0
.go_on_write:
mov ax,[si]
out dx,ax
add si,2
loop .go_on_write
ret

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

之前我們介紹過讀硬盤操作和寫硬盤操作都是7個步驟,其中只有第5步和第7步不同,其它步驟完全相同,大家可以和上一講中的代碼對比看一下。
下面我們將boot2.asm編譯並寫入到虛擬硬盤的第一個扇區:

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

此時用hexdum命令查看一下虛擬硬盤第二個扇區當前的數據,截圖如下:

從上面的截圖可以看到,此時虛擬硬盤第二個扇區前3個字節依次爲1、2、3,最後3個字節依次爲3、2、1。
下面我們以調試模式運行QEMU:

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

通過GDB連接到QEMU,直接輸入GDB命令c,讓程序運行幾秒鐘,然後Ctrl+C,讓程序暫停。此時寫硬盤程序應該已經運行完了。此時查看一下內存0x7e00~0x7fff的數據:

(gdb) x /512xb 0x7e00

從上面截圖可以看到,在內存0x7e00~0x7fff的數據中,前3個字節依次爲4、5、6,最後3個字節依次爲6、5、4,其餘全是0。如果程序運行正確的話,此時硬盤第二扇區中的數據與此相同。
下面我們退出GDB,並關閉QEMU。然後用hexdum命令再查看一下虛擬硬盤第二個扇區的數據,截圖如下:

從上面截圖中可以看到,硬盤第二扇區的數據與內存中0x7e00~0x7fff的數據一致,說明寫入成功,實驗完畢。


本講視頻版地址:https://www.bilibili.com/video/BV1Hk4y187Bw/
配套的代碼與資料在:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS操作系統交流QQ羣:643474045

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