Chapter 3:增強 MBR
這是讀書筆記

作者:鄭鋼
出版社:佳魁資訊股份有限公司
出版日期:2017/05/31
這邊討論都是 x86 架構下的組合語言,組譯工具是 nasm
,
如果是 ARM 架構下的組合語言,組譯工具是 armasm
。
位址、section、vstart
- 編譯器的主要工作就是給各種符號編址。
- CPU 無法判斷是指令還是一般資料。
- 組合語言裡面的 section 僅是在邏輯上方便程式開發人員整理程式用。
- vstart 是虛擬的起始位址,loader 應該要根據其位址載入到記憶體相對應位址。
CPU 的真實模式

參考資料:CPU Registers x86
顯示器
x86 I/O 通訊
- Intel x86 的 I/O 是使用 PMI/O。
顯示卡、顯示記憶體、顯示器

改寫 MBR,直接操作顯示卡
Source Code
Compile
Hard Disk Image
Result

bochs 偵錯方法
查看 help 資訊

查看 BIOS 的入口點:0xFFFF0

反組譯機器碼

查看 MBR 的入口點:0x7c00
一開始是沒有值,BIOS 負責把 MBR 從硬碟載到 0x7c00
順便可以看看 BIOS 吐出來的資訊,而游標的位置就是上一章的範例,MBR 印出字元的位置。

硬碟介紹
如何操控硬碟
參考資料:Bochs' map of I/O ports to functions
0x1F7 / 0x177 Status Register for read.

資料傳送方式
- CPU 直接取資料:registers, memory.
- Polling
- Interrupt
- DMA (硬體需支援)
- I/O處理器 (硬體需支援)
MBR 載入 Loader
載入硬碟資料
Source Code
boot.inc
mbr.S
;主引導程序
;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00
mov ax,0xb800
mov gs,ax
; 清屏
;利用0x06號功能,上卷全部行,則可清屏。
; -----------------------------------------------------------
;INT 0x10 功能號:0x06 功能描述:上卷窗口
;------------------------------------------------------
;輸入:
;AH 功能號= 0x06
;AL = 上卷的行數(如果為0,表示全部)
;BH = 上卷行屬性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;無返回值:
mov ax, 0600h
mov bx, 0700h
mov cx, 0 ; 左上角: (0, 0)
mov dx, 184fh ; 右下角: (80,25),
; 因為VGA文本模式中,一行只能容納80個字符,共25行。
; 下標從0開始,所以0x18=24,0x4f=79
int 10h ; int 10h
; 輸出字符串:MBR
mov byte [gs:0x00],'1'
mov byte [gs:0x01],0xA4
mov byte [gs:0x02],' '
mov byte [gs:0x03],0xA4
mov byte [gs:0x04],'M'
mov byte [gs:0x05],0xA4 ;A表示綠色背景閃爍,4表示前景色為紅色
mov byte [gs:0x06],'B'
mov byte [gs:0x07],0xA4
mov byte [gs:0x08],'R'
mov byte [gs:0x09],0xA4
mov eax,LOADER_START_SECTOR ; 起始扇區lba地址
mov bx,LOADER_BASE_ADDR ; 寫入的地址
mov cx,1 ; 待讀入的扇區數
call rd_disk_m_16 ; 以下讀取程序的起始部分(一個扇區)
jmp LOADER_BASE_ADDR
;-------------------------------------------------------------------------------
;功能:讀取硬盤n個扇區
rd_disk_m_16:
;-------------------------------------------------------------------------------
; eax=LBA扇區號
; ebx=將數據寫入的內存地址
; ecx=讀入的扇區數
mov esi,eax ;備份eax
mov di,cx ;備份cx
;讀寫硬盤:
;第1步:設置要讀取的扇區數
mov dx,0x1f2
mov al,cl
out dx,al ;讀取的扇區數
mov eax,esi ;恢覆ax
;第2步:將LBA地址存入0x1f3 ~ 0x1f6
;LBA地址7~0位寫入端口0x1f3
mov dx,0x1f3
out dx,al
;LBA地址15~8位寫入端口0x1f4
mov cl,8
shr eax,cl
mov dx,0x1f4
out dx,al
;LBA地址23~16位寫入端口0x1f5
shr eax,cl
mov dx,0x1f5
out dx,al
shr eax,cl
and al,0x0f ;lba第24~27位
or al,0xe0 ; 設置7~4位為1110,表示lba模式
mov dx,0x1f6
out dx,al
;第3步:向0x1f7端口寫入讀命令,0x20
mov dx,0x1f7
mov al,0x20
out dx,al
;第4步:檢測硬盤狀態
.not_ready:
;同一端口,寫時表示寫入命令字,讀時表示讀入硬盤狀態
nop
in al,dx
and al,0x88 ;第4位為1表示硬盤控制器已準備好數據傳輸,第7位為1表示硬盤忙
cmp al,0x08
jnz .not_ready ;若未準備好,繼續等。
;第5步:從0x1f0端口讀數據
mov ax, di
mov dx, 256
mul dx
mov cx, ax ; di為要讀取的扇區數,一個扇區有512字節,每次讀入一個字,
; 共需di*512/2次,所以di*256
mov dx, 0x1f0
.go_on_read:
in ax,dx
mov [bx],ax
add bx,2
loop .go_on_read
ret
times 510-($-$$) db 0
db 0x55,0xaa
Compile
Hard Disk Image
準備一個簡單的 Loader
Source Code
loader.S
Compile
Hard Disk Image
Result
