读取硬盘数据
通过硬盘端口读取
硬盘端口:
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
如果正确读写数据,就可以继续执行,如果出现错误,可以和前面的错误一起写一个错误处理