通過硬盤端口讀取
硬盤端口:
0x1f0 ~ 0x1f7 8個端口
讀寫模式:
- CHS
傳入磁頭,柱面,扇區信息 - LBA
傳入邏輯塊起始,讀取邏輯塊數量
與端口通信:
in dest[al / ax], src[dx / i8] ;從端口讀入
out dest[dx / i8], src[al / ax] ;寫入端口
選擇ax和選擇al的差別在於,若端口是8位,則用al,若端口是16位,則用ax
用 LBA28 讀取硬盤數據
LBA28是用一個28位的數表示邏輯扇區號的方法,最多可以讀取128GB的硬盤
各個端口功能:
0x1f0:16位端口,讀取數據的位置
0x1f1:錯誤寄存器,包含硬盤驅動器最后一次執行命令的狀態(錯誤原因)
0x1f2 ~ 0x1f7:8位端口
0x1f2:要讀取的扇區數
0x1f3~0x1f6(低4位):要讀取的第一塊邏輯扇區號(共28位)
0x1f6(高4位):讀取方式設置:標識硬盤號和讀寫模式
第4位:選擇硬盤號(0:主硬盤,1:從硬盤)
第6位:選擇讀寫模式(0:CHS,1:LBA)
(從第0位開始數)
0x1f7:選擇寫讀或寫:為0x20時表示讀取硬盤,為0x30時表示寫硬盤
這部分代碼為:
;常量部分
HDDPORT0 equ 0x1f0
HDDREADSET equ 0xe0 ;0b11100000
HDDREADCODE equ 0x20
;變量
StartDiskIndex dd 2 ;
DiskAmount db 1
readHdd:
;讀取硬盤數量
mov al, [DiskAmount]
mov dx, HDDPORT + 2 ;dx = 0x1f2
out dx, al
;寫入起始硬盤號前16位
mov ax, [ReadStart]
inc dx ;dx = 0x1f3
out dx, al
mov al, ah
inc dx ;dx = 0x1f4
out dx, al
;寫入硬盤號第17到28位
mov ax, [ReadStart + 2]
inc dx ;dx = 0x1f5
out dx, al
mov al, ah
mov ah, HDDREADSET ;將硬盤讀寫模式和讀取哪個硬盤整合到al的高4位
or al, ah
inc dx ;dx = 0x1f6
out dx, al
;表示要讀取硬盤
mov al, HDDREADCODE
inc dx ;dx = 0x1f7
out dx, al
在寫入必要的信息后,我們就要等待硬盤給出回復
回復是保存在0x1f7端口的狀態碼,我們只需要第7位和第3位的信息
第7位為1時,表示硬盤正忙,為0時表示硬盤空閑;第3位為1時表示硬盤已准備好,為0時表示還未准備好
這段代碼如下:
STATECODE equ 0x88 ;0b10001000
READCODE equ 0x08 ;0b00001000
.wiats: ;等待
in al, dx
and al, STATECODE
cmp al, READCODE
jnz .waits
最后從硬盤中讀取數據
示例中我要們讀取一個完整的扇區,即512字節
我們可以以字節為單位讀,也可以以字為單位讀
這里用以字為單位讀
mov dx, HDDPORT0
mov cx, 256
.readWord:
in ax, dx
mov [ds:si], ax ;ds:si為目標內存,換成哪里都可以
add si, 2
loop .readWord
通過int 13拓展讀取硬盤
首先,我們需要一個結構體,它長這樣:
DiskAddressPacekt:
PackSize db 10h
Reserved db 0
BlockCount dw 0
BufferOffset dw 0
BufferSegment dw 0
BlockLow dd 0
BlockHigh dd 0
其中:
PackSize這里固定為16,表示這個包的大小
Reserved表示預留的字節
BlockCount表示將要讀取的扇區數
BufferOffset表示目標地址的偏移地址
BufferSegment表示目標地址的段地址
BlockLow表示起始扇區號的前四個字節
BlockHigh表示起始扇區號的后三個字節
我們還需要測試一下,這台機器是不是可以使用int 13擴展
我們這樣測試:
.checkInt13:
mov ah, 41h ;檢查用
mov bx, 55aah
mov dl, 80h
int 13h
cmp bx, 0aa55h
jnz ErrCatch
如果擴展可用,我們就繼續進入讀寫環節:
.readDisk:
mov ah, 42h ;讀取用
mov dl, 80h
mov si, DiskAddressPacekt
int 13h
test ah, ah
jnz ErrCatch
.writeDisk:
mov ah, 43h ;寫入用
mov dl, 80h
mov si, DiskAddressPacekt
int 13h
test ah, ah
jnz ErrCatch
如果正確讀寫數據,就可以繼續執行,如果出現錯誤,可以和前面的錯誤一起寫一個錯誤處理