DiskDataReg equ 0x01f0
DiskErrReg equ 0x01f1
DiskSectCntReg equ 0x01f2
DiskLoLBAAddr equ 0x01f3
DiskMeLBAAddr equ 0x01f4
DiskHiLBAAddr equ 0x01f5
DiskModReg equ 0x01f6
DiskCmdStatReg equ 0x01f7
DiskReadCmd equ 0x20
DiskWriteCmd equ 0x30
Arg1Off equ 0x04 ;第一个参数相对bp偏移
Arg2Off equ 0x06 ;第二个参数相对bp偏移
Arg3Off equ 0x08 ;第三个参数相对bp偏移
Arg4Off equ 0x0A ;第四个参数相对bp偏移
StackBase equ 0x0000
StackEnd equ 0x2000
DataBase equ 0x0300
DataEnd equ 0x1FFF
section code align=16 vstart=0x7c00
jmp entry
SetSectAddr:
;设置逻辑扇区的地址
push bp
mov bp,sp
push bx
;发扇区总数
mov dx,DiskSectCntReg
mov al,byte [bp+Arg4Off]
out dx,al
;发扇区地址
mov dx,DiskLoLBAAddr
mov al,byte [bp+Arg3Off]
out dx,al
mov dx,DiskMeLBAAddr
mov al,byte [bp+Arg3Off+1]
out dx,al
mov dx,DiskHiLBAAddr
mov al,byte [bp+Arg2Off]
out dx,al
mov dx,DiskModReg
mov al,byte [bp+Arg2Off+1]
out dx,al
pop bx
mov sp,bp
pop bp
ret
WaitDiskReady:
;等待磁盘就绪
mov dx,DiskCmdStatReg
.waits:
in al,dx
and al,0x88
cmp al,0x08
jnz .waits
;判断是否有错误
mov dx,DiskErrReg
.getErr:
in al,dx
cmp al,0x00
;al不为0出错
jnz .resume
;没有出错 返回0
xor ax,ax
ret
.resume:
;出错 返回
mov ax,0x01
ret
ReadFromDisk:
call SetSectAddr
;发读命令
mov dx,DiskCmdStatReg
mov al,DiskReadCmd
out dx,al
call WaitDiskReady
;读取保存在扇区上的数据的有效长度
mov dx,DiskDataReg
in ax,dx
shr ax,0x01
;比较要读取数据的长度和有效数据的长度,取最短的
;磁盘上保存的数据,长度按字节计数,但是DiskDataReg
;端口是16位端口,每次读取1字,因此循环次数需要除2
mov cx,ax
mov dx,DiskDataReg
.readw:
in ax,dx
mov [bx],ax
add bx,2
loop .readw
;代码没写好 没返回地址 只能自己构造返回地址了
lea ax,[RetFromReadDisk]
push ax
ret
entry:
xor ax,ax
mov ax,DataBase
mov ds,ax
mov ax,StackBase
mov ss,ax
mov sp,StackEnd
;读取扇区总数
push word 0x0001
;LBA地址的0-15位
push word 0x0001
;LBA地址的16-31位
push word 0xe000
;需要从扇区上读取的最大字节数
push word 0x0200
jmp ReadFromDisk
RetFromReadDisk:
jmp $
times 510-($-$$) db 0
db 0x55,0xaa
len dw 0x000c ;后面有效数据的长度
string db 'Hello world',0