📄 hdd.8
字号:
; AH=0C: seek
;
hd_seek: call hd_sel ;select drive
jb hd_seek9
call hd_chs ;set CHS value
mov al,70h
call hd_cmd ;seek command
jb hd_seek9
call hd_stat ;check status
hd_seek9: cmp al,40h ;seek error ?
jnz hd_seek91
mov al,0 ;don't show it... (Core test will fail
hd_seek91: jmp hd_exit0 ;otherwise)
;
; AH=10: test drive ready
;
hd_trdy: mov cx,0ffffh ;no time-out
call hd_sel0 ;select drive, test ready
jb hd_trdy9
mov dl,low(hdc_stat) ;check status
in al,dx
mov [m_hdst],al
mov ah,0aah ;not ready
test al,40h
jz hd_trdy8
mov ah,40h ;seek error
test al,10h
jz hd_trdy8
mov ah,0cch ;write fault
test al,20h
jnz hd_trdy8
mov ah,0 ;ok status
hd_trdy8: mov al,ah
hd_trdy9: jmp hd_exit0
;
; AH=11: recalibrate
;
hd_recal: call hd_sel ;select drive
mov al,10h
call hd_cmd ;recalibrate command
jb hd_rec9
call hd_stat ;get status
hd_rec9: jmp hd_exit0
;
; AH=14: controller diagnostics
;
hd_diag: call hd_busy18 ;wait for not busy
mov al,20h ;bad controller
jb hd_diag9 ;:bad
mov al,90h ;diagnostic command
mov dx,hdc_cmd
out dx,al
out iowait,al
mov cx,18*6 ;max. 6 seconds (!!!)
call hd_busy ;wait for not busy
mov al,80h ;time-out
jb hd_diag9
mov dx,hdc_err ;check error register
in al,dx
and al,7fh
sub al,1
jz hd_diag9 ;:ok
mov al,20h ;bad controller
hd_diag9: jmp hd_exit0
;
; AH=15: read DASD type
;
hd_gettyp: call hd_parm ;get pointer to parameter block
jb hd_gett8 ;:not present
mov al,[cs:di.dpt_head] ;number heads
mul byte [cs:di.dpt_sec] ;number sectors
mov dx,[cs:di.dpt_cyl] ;number cylinders
dec dx ;minus one for diagnostics
mul dx
mov cl,3 ;drive present
jmp short hd_gett9
hd_gett8: xor ax,ax ;0 = drive not present
xor cx,cx
xor dx,dx
hd_gett9: mov byte [bp._ah],cl ;0 = not present, 3 = present
mov [bp._cx],dx ;CX = MSB sector count
mov [bp._dx],ax ;DX = LSB sector count
mov al,0 ;ok status
mov [m_hdstat],al
jmp hd_exit1
;
; AH = 24: set multiple mode
;
hd_setmul: call hd_sel ;select drive
mov dl,low(hdc_cnt)
mov al,[bp._al] ;number of sectors
out dx,al
mov al,0c6h
call hd_cmd ;set multiple mode command
jb hd_setm9
call hd_stat ;get status
hd_setm9: jmp hd_exit0
;
; AH=25: identify drive
;
hd_id: call hd_selb ;select drive
;ignore time-out here, if drive not ready
;(ATAPI drive doesn't report ready
;until spoken to)
mov al,0ech ;identify drive
call hd_cmd ;issue command
jb hd_id9 ;:bad drive
in al,dx ;hdc_stat
test al,1 ;error ?
jz hd_id1 ;:no
hd_id0: mov al,0a1h ;ATAPI identify drive
call hd_cmd ;issue command
jb hd_id9 ;:time-out
hd_id1: xor cx,cx
hd_id2: in al,dx ;hdc_stat
test al,8 ;DRQ ?
jnz hd_id3 ;:yes
loop hd_id2
mov al,80h ;time-out
jmp short hd_id9
hd_id3: cld ;forward direction
mov dl,low(hdc_dat)
mov cx,256 ;512 bytes
mov di,bx ;destination
rep insw ;read data
call hd_stat ;get status
hd_id9: jmp hd_exit0 ;exit
#if def HD_EDD
;
; AH=41: detect EDD support
;
hd_edd41: cmp bx,55aah ;magic cookie ?
jnz hd_edd419 ;no: bad
mov word [bp._bx],0aa55h ;return cookie
mov word [bp._cx],1 ;support packet commands; no lock /
;eject
mov byte [bp._ah],1 ;major version
mov byte [m_hdstat],0
jmp hd_exit2 ;return carry clear
hd_edd419: jmp hd_badcmd ;return error
;
; AH=42: extended read
;
hd_xrd: call hd_sel ;select drive
jb hd_xrd9
call hd_xadr ;handle address
jb hd_xrd9
mov byte [m_hdflag],0 ;clear interrupt flag
mov al,20h ;issue read command
mov dx,hdc_cmd
out dx,al
hd_xrd1: call hd_int ;wait for interrupt
jb hd_xrd9
mov dl,low(hdc_stat) ;read status
in al,dx
mov byte [m_hdflag],0 ;clear interrupt flag for next
test al,1 ;ERR ?
jnz hd_xrd8
test al,8 ;DRQ ?
jz hd_xrd8 ;:no
mov dl,low(hdc_dat) ;read 512 bytes from drive
mov cx,256
rep insw
dec bl ;another sector ?
jnz hd_xrd1 ;:yes
hd_xrd8: mov es,[bp._ds] ;access address packet
sub byte [es:si+drq_blk],bl ;adjust sector count to reality
call hd_stat ;get status
hd_xrd9: jmp hd_exit0
;
; AH=43: extended write
;
hd_xwr: call hd_sel ;select drive
jb hd_xwr9
call hd_xadr ;handle address
jb hd_xwr9
mov si,di ;buffer ^
mov al,30h ;issue write command
mov dx,hdc_cmd
out dx,al
hd_xwr1: mov dl,low(hdc_stat) ;read status
xor cx,cx
mov byte [m_hdflag],0 ;clear interrupt flag for next
hd_xwr2: in al,dx
test al,8 ;DRQ ?
jnz hd_xwr3 ;:yes
test al,21h ;error ?
jnz hd_xwr8
loop hd_xwr2
mov al,80h ;time-out
jmp short hd_xwr9
hd_xwr3: mov dl,low(hdc_dat) ;write 512 bytes from drive
mov cx,256
es: rep outsw
call hd_int ;wait for interrupt
jb hd_xwr9
dec bl ;another sector ?
jnz hd_xwr1 ;:yes
hd_xwr8: call hd_stat ;get status
hd_xwr9: mov es,[bp._ds] ;access address packet
mov si,[bp._si]
sub byte [es:si+drq_blk],bl ;adjust sector count to reality
jmp hd_exit0
;
; AH=44: extended verify
;
hd_xver: call hd_sel ;select drive
jb hd_xver9
call hd_xadr ;handle address
jb hd_xver9
mov al,40h
call hd_cmd ;read verify command
jb hd_xver9
call hd_stat ;get status
hd_xver9: jmp hd_exit0
;
; AH=47: extended seek
;
hd_xsk: call hd_sel ;select drive
jb hd_xsk9
call hd_xadr ;handle address
jb hd_xsk9
mov al,70h
call hd_cmd ;seek command
jb hd_xsk9
call hd_stat ;check status
hd_xsk9: jmp hd_exit0
;
; AH=48: return drive parameters
;
; Note: Phoenix spec says we should return PHYSICAL geometry, but
; Award BIOS returns LOGICAL... Users of this function are most
; interested in the max sector count anyway.
;
hd_edd48: call hd_parm ;get ^parameter block -> DI
jb hd_edd489
mov si,di ;^parameter block
cld ;forward direction
mov es,[bp._ds] ;buffer segment
mov di,[bp._si] ;buffer offset
mov al,1 ;(error code)
cmp word [es:di],26 ;buffer at least 26 bytes long
jb hd_edd489 ;less -> error
mov ax,26 ;buffer length
stosw
mov ax,2 ;flags: valid geometry
stosw
xor eax,eax
mov ax,[cs:si.dpt_cyl] ;number of cylinders
stosd
mov al,[cs:si.dpt_head] ;number of heads
mov ah,0
stosd
mov al,[cs:si.dpt_sec] ;number of sectors
; mov ah,0
stosd
mov al,[cs:si.dpt_head] ;number heads
mul byte [cs:si.dpt_sec] ;number sectors
mov dx,[cs:si.dpt_cyl] ;number cylinders
mul dx
stosw ;-> physical sector count
xchg ax,dx
stosw
xor eax,eax
stosd
mov ax,512 ;bytes per sector
stosw
mov al,0 ;ok status
hd_edd489: jmp hd_exit0
;
; write LBA address to command file
;
; returns sector count in BL, transfer address in ES:DI
;
; this will break on old drives that don't support LBA
;
hd_xadr: mov es,[bp._ds] ;restore segment, SI still OK
cmp byte [es:si+drq_len],16 ;at least 16 bytes
jb hd_xadr9 ;:error
mov dx,hdc_cnt ;sector count
mov al,[es:si+drq_blk]
mov bl,al ;return in BL
out dx,al
inc dx
mov eax,[es:si+drq_lba] ;LBA sector number
out dx,al ;hdc_sec sector = LBA 7..0
inc dx
shr ax,8
out dx,al ;hdc_cyl cylinder low = LBA 15..8
inc dx
shr eax,16
out dx,al ;hdc_cyh cylinder high = LBA 23..16
inc dx
in al,dx ;hdc_drv get drive
and al,0b0h ;keep reserved, drive select bits
or al,40h ;set LBA mode
or al,ah
out dx,al ;hdc_drv heads = LBA27..24
mov di,[es:si+drq_ofs] ;get ^transfer buffer
mov es,[es:si+drq_seg]
cld ;forward mode
clc ;ok
ret
hd_xadr9: mov al,1 ;return error
stc
ret
#endif
;
; wait for not busy, check status
;
hd_stat0: call hd_busy18 ;wait until not busy
jb hd_stat9
; Enter here for faster service (assuming normally not busy)
; This is arranged to get fastest response when no error.
hd_stat: mov dx,hdc_stat ;test whether busy
in al,dx
test al,80h
jnz hd_stat0 ;:busy
mov [m_hdst],al
mov ah,al ;save status
test al,24h ;write fault / ECC ?
jnz hd_stat1
and al,50h ;not ready, or seek error ?
cmp al,50h
jnz hd_stat2
test ah,1 ;other error ?
jnz hd_stat3
mov al,0 ;return ok status
ret
hd_stat1: mov al,11h ;ECC corrected data
test ah,4
jnz hd_stat9
mov al,0cch ;no - must be write fault
hd_stat9: stc
ret
hd_stat2: mov al,0aah ;not ready
test ah,40h
jz hd_stat9
mov al,40h ;no - must be seek error
stc
ret
hd_stat3: mov dl,low(hdc_err) ;read error register
in al,dx
mov [m_hderr],al
mov si,hd_errtab
cmp al,0 ;nothing set -> undefined error
jz hd_stat5
hd_stat4: inc si
shl al,1
jnb hd_stat4
hd_stat5: mov al,[cs:si] ;get error code
stc
ret
;
; error register -> error code translation
;
hd_errtab: db 0e0h ;nothing set - status error
db 0ah ;80 - bad sector flag detected
db 10h ;40 - bad ECC
db 0bbh ;20 - undefined error
db 04h ;10 - record not found
db 01h ;08 - abort -> bad command
db 0bbh ;04 - undefined error
db 40h ;02 - seek error
db 02h ;01 - address mark not found
;
; get pointer to parameter block
;
; entry: DL = drive
; exit: CS:DI = parameter block
;
hd_parm: and dl,7fh
cmp dl,[m_hdcnt] ;legal drive number ?
jae hd_parm9 ;:bad
mov di,hd_prm1
test dl,1 ;(clc)
jnz hd_parm2
mov di,hd_prm0
hd_parm2: ret
hd_parm9: mov al,1 ;error code
stc
ret
;
; wait while HD busy, CX ticks
;
hd_busy18: mov cx,18 ;18 ticks = 1 second
hd_busy: add cx,[m_timer] ;start time + max number of ticks
mov dx,hdc_stat
hd_busy1: in al,dx
test al,80h ;busy ?
jz hd_busy9 ;:no, carry clear
cmp cx,[m_timer]
jns hd_busy1 ;keep waiting
hd_busy8: stc ;time-out
mov al,80h ;status code
hd_busy9: ret
;
; select drive, wait for drive ready
;
; -> CS:DI = ^parameter block
;
; special entry: no drive number check
hd_selb: mov cx,18 ;1 s time-out
and dl,7fh ;mask drive number
jmp short hd_sel0a
; normal entry
hd_sel: mov cx,18 ;1 s time-out for ready wait
hd_sel0: and dl,7fh ;legal drive number ?
cmp dl,[m_hdcnt]
jae hd_parm9 ;:bad
hd_sel0a: mov di,hd_prm1
test dl,1 ;(clc)
jnz hd_sel1
mov di,hd_prm0
hd_sel1: mov byte [m_hdflag],0 ;clear interrupt flag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -