📄 hdd.8
字号:
;
; Hard Disk BIOS
;
; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.
;
; Limitations:
;
; - HDD must support command EC (identify device).
; - Read Long, Write Long (hardware-specific number of ECC bytes,
; rarely used) not supported
; - Format not supported (not available on IDE drives)
; - Only one drive supported
; - Only AMI / Intel style of CHS translation supported.
; (simple bit shift would be simpler, but messes up sequential
; transfer rate)
; - Extended disk address mode only works with drives that support
; LBA.
;
; Notes:
;
; - Storage of disk parameters requires read/write shadow during POST
; (can be write protected later). This code will break if shadow
; is write protected during drive configuration.
;
; pd 001019 - add option HD_EDD -> packet interface
; pd 001019 - add functions 41 and 48 to support large drives.
; pd 001017 - fix power saving HLT to avoid race conditions.
; pd 001017 - don't limit cylinder number to 1023 in hd_lba
; (ensure correct result for function 15), do limit in
; function 08.
; pd 000211 - recognize new SanDisk ID
; pd 991020 - add hd_top variable, needed to support M-Systems
; DiskOnChip.
; pd 990501 - add CDBOOT hook
; pd 990427 - add ATAPI identify
; pd 990214 - add hook for IDE speed initialization (cs_ide)
; pd 990210 - add LBA mode support
; pd 981010 - fix read handshake
; pd 980710 - fix function 15: return 0 if drive not present
#if def DEBUG
HD_DEBUG: ;& comment out for production code
#endif
;
; drive parameter structure (stored in data module)
;
dpt_cyl equ 0 ;number of cylinders
dpt_head equ 2 ;number of heads
dpt_sig equ 3 ;signature, $A0
dpt_psec equ 4 ;physical sectors per track
dpt_mul equ 5 ;(precompensation) -> multiple count
dpt_shl equ 7 ;reserved -> shift count
dpt_ctl equ 8 ;drive control byte
dpt_pcyl equ 9 ;physical cylinders
dpt_phd equ 11 ;physical heads
dpt_lz equ 12 ;(landing zone)
dpt_sec equ 14 ;logical sectors per track
dpt_res equ 15 ;reserved
dpt_len equ 16 ;length of structure
;
; disk address packet for extended read/write/verify/seek
;
#if def HD_EDD
drq_len equ 0 ;packet size in bytes
drq_res equ 1 ;reserved, must be 0
drq_blk equ 2 ;number of blocks, max. 127
drq_res2 equ 3 ;reserved, must be 0
drq_ofs equ 4 ;transfer buffer offset
drq_seg equ 6 ;transfer buffer segment
drq_lba equ 8 ;block number (8 bytes)
#endif
#if def FLASHDISK
int40: dec dl ;correct floppy drive number
int 40h ;execute floppy interrupt
inc dl ;restore drive number
retf 2 ;return, don't change status
intfld: jmp fldisk
;
; INT 13 entry
;
int13hd: sti
and dl,dl ;flash disk ?
jz intfld
jns int40 ;:floppy
and ah,ah ;reset drive ?
jnz int13hd1 ;:no
cmp dl,81h ;above valid HDD ?
ja int40 ;-> floppy only
int 40h ;reset floppy
mov ah,0
#else
#if def CDBOOT
; redirect to floppy or CD emulation as needed
int40: test byte [cs:d_cdflag],1 ;emulation enabled ?
jz int40a ;:no
test dl,dl ;drive 0 ?
jnz int40b ;:no
jmp cddisk
int40a: int 40h ;execute floppy interrupt
retf 2 ;return, don't change status
int40b: dec dl ;correct floppy drive number
int 40h ;execute floppy interrupt
inc dl ;restore drive number
retf 2 ;return, don't change status
#else
; execute floppy interrupt
int40: int 40h ;execute floppy interrupt
retf 2 ;return, don't change status
#endif
;
; INT 13 entry
;
int13hd: sti
and dl,dl ;HDD ?
jns int40 ;:floppy
cmp dl,byte [cs:hd_top] ;compare with max drive number
jae int40 ;:floppy or DiskOnChip
and ah,ah ;reset drive ?
jnz int13hd1 ;:no
cmp dl,81h ;above valid HDD ?
ja int40 ;-> floppy only
int 40h ;reset floppy
mov ah,0
#endif
;
; dispatch disk commands
;
int13hd1: push ds ;save registers
push es
pusha
mov bp,sp ;access to stack frame
xor di,di ;access BIOS segment
mov ds,di
#if def HD_DEBUG
; test byte [m_kbf],kb_fscrs ;scroll lock ?
; jnz int13dmp1 ;yes: don't display
call v_dump ;& dump registers
int13dmp1:
#endif
mov di,ax ;command -> index
shr di,8
add di,di
and byte [bp+18h],0feh ;clear return carry
cmp di,hd_vec99-hd_vectab ;limit command vector
jae hd_badcmd ;:too high
jmp [cs:di.hd_vectab] ;jump to command
;
; Illegal command
;
hd_badcmd: mov byte [m_hdstat],1 ;illegal command
;
; AH=01: get status
;
hd_status: mov al,[m_hdstat] ;get old status
mov [bp._al],al ;return in AL
;
; return status
;
hd_exit0: mov [m_hdstat],al ;set error code
mov [bp._ah],al ;return in AH
hd_exit1: and al,al ;error ?
jz hd_exit2 ;:no
or byte [bp+18h],1 ;yes: set carry
#if def HD_DEBUG
stc
hd_exit2: pushf
test byte [m_kbf],kb_fscrs ;scroll lock ?
jnz int13dmp2 ;yes: don't display
call v_dump2 ;& dump registers
int13dmp2: popf
#else
hd_exit2:
#endif
popa ;restore registers
pop es
pop ds
iret ;return from interrupt
;
; IDE vector table
;
even
hd_vectab: dw hd_rst ;AH=00: recalibrate drive
dw hd_status ;AH=01: get status
dw hd_read ;AH=02: read
dw hd_write ;AH=03: write
dw hd_verify ;AH=04: verify
dw hd_badcmd ;AH=05: format track -> not supported
dw hd_badcmd ;AH=06: bad
dw hd_badcmd ;AH=07: bad
dw hd_getprm ;AH=08: read drive parameters
dw hd_setprm ;AH=09: set drive parameters
dw hd_badcmd ;AH=0A: read long -> not supported
dw hd_badcmd ;AH=0B: write long -> not supported
dw hd_seek ;AH=0C: seek
dw hd_rst2 ;AH=0D: alternate disk reset (HD only)
dw hd_badcmd ;AH=0E: bad
dw hd_badcmd ;AH=0F: bad
dw hd_trdy ;AH=10: test drive ready
dw hd_recal ;AH=11: recalibrate
dw hd_badcmd ;AH=12: bad
dw hd_badcmd ;AH=13: bad
dw hd_diag ;AH=14: controller diagnostics
dw hd_gettyp ;AH=15: get drive type
dw hd_badcmd ;AH=16: bad
dw hd_badcmd ;AH=17: bad
dw hd_badcmd ;AH=18: bad
dw hd_badcmd ;AH=19: bad
dw hd_badcmd ;AH=1A: bad
dw hd_badcmd ;AH=1B: bad
dw hd_badcmd ;AH=1C: bad
dw hd_badcmd ;AH=1D: bad
dw hd_badcmd ;AH=1E: bad
dw hd_badcmd ;AH=1F: bad
dw hd_badcmd ;AH=20: bad
dw hd_badcmd ;AH=21: bad
dw hd_badcmd ;AH=22: bad
#if def HD_TIME
dw hd_timer ;AH=23: set standby timer NON-STANDARD
#else
dw hd_badcmd
#endif
dw hd_setmul ;AH=24: set multiple mode
dw hd_id ;AH=25: identify drive
#if def HD_EDD
dw hd_badcmd ;AH=26: bad
dw hd_badcmd ;AH=27: bad
dw hd_badcmd ;AH=28: bad
dw hd_badcmd ;AH=29: bad
dw hd_badcmd ;AH=2A: bad
dw hd_badcmd ;AH=2B: bad
dw hd_badcmd ;AH=2C: bad
dw hd_badcmd ;AH=2D: bad
dw hd_badcmd ;AH=2E: bad
dw hd_badcmd ;AH=2F: bad
dw hd_badcmd ;AH=30: bad
dw hd_badcmd ;AH=31: bad
dw hd_badcmd ;AH=32: bad
dw hd_badcmd ;AH=33: bad
dw hd_badcmd ;AH=34: bad
dw hd_badcmd ;AH=35: bad
dw hd_badcmd ;AH=36: bad
dw hd_badcmd ;AH=37: bad
dw hd_badcmd ;AH=38: bad
dw hd_badcmd ;AH=39: bad
dw hd_badcmd ;AH=3a: bad
dw hd_badcmd ;AH=3b: bad
dw hd_badcmd ;AH=3c: bad
dw hd_badcmd ;AH=3d: bad
dw hd_badcmd ;AH=3e: bad
dw hd_badcmd ;AH=3f: bad
dw hd_badcmd ;AH=40: bad
dw hd_edd41 ;AH=41: detect extended interface
dw hd_xrd ;AH=42: extended read
dw hd_xwr ;AH=43: extended write
dw hd_xver ;AH=44: extended verify
dw hd_badcmd ;AH=45: bad (lock / unlock drive)
dw hd_badcmd ;AH=46: bad (eject removable media)
dw hd_xsk ;AH=47: extended seek
dw hd_edd48 ;AH=48: get extended parameters
#endif
hd_vec99: ;end of table
;
; AH=00: reset hard disk drives
; AH=0D: alternate reset (doesn't reset floppy)
;
hd_rst:
hd_rst2: cli
in al,pic1+1 ;enable HD interrupt
and al,0bfh
out iowait,ax
out pic1+1,al
in al,pic0+1 ;enable cascade interrupt
and al,0fbh
out iowait,ax
out pic0+1,al
sti
mov dx,hdc_ctrl
mov al,4 ;soft reset
out dx,al
out iowait,ax ;wait a bit
out iowait,ax
out iowait,ax
out iowait,ax
out iowait,ax
mov al,0 ;end of reset, interrupt enable
out dx,al ;hdc_ctrl
call hd_busy18 ;wait while busy
jb hd_rst8 ;:error
mov dx,hdc_err ;check error status
in al,dx
and al,7fh
sub al,1
jnz hd_rst8 ;:bad status
mov al,0 ;ok status
jmp hd_exit0 ;return
hd_rst8: mov al,5 ;reset failed
hd_rst9: jmp hd_exit0
;
; AH=02: read sectors
;
hd_read: call hd_sel ;select drive
jb hd_read9
call hd_chs ;translate CHS
jb hd_read9
mov bl,[bp._al] ;get sector count
cld ;forward mode
mov di,[bp._bx] ;get destination address
mov byte [m_hdflag],0 ;clear interrupt flag
mov al,20h ;issue read command
mov dx,hdc_cmd
out dx,al
hd_read1: call hd_int ;wait for interrupt
jb hd_read9
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_read8
test al,8 ;DRQ ?
jz hd_read8 ;:no
mov dl,low(hdc_dat) ;read 512 bytes from drive
mov cx,256
rep insw
dec bl ;another sector ?
jnz hd_read1 ;:yes
hd_read8: sub byte [bp._al],bl ;adjust sector count to reality
call hd_stat ;get status
hd_read9: jmp hd_exit0
;
; AH=03: write sectors
;
hd_write: mov si,bx ;source address
call hd_sel ;select drive
jb hd_writ9
call hd_chs ;translate CHS
jb hd_writ9
mov bl,[bp._al] ;get sector count
cld ;forward mode
mov al,30h ;issue write command
mov dx,hdc_cmd
out dx,al
hd_writ1: mov dl,low(hdc_stat) ;read status
xor cx,cx
mov byte [m_hdflag],0 ;clear interrupt flag for next
hd_writ2: in al,dx
test al,8 ;DRQ ?
jnz hd_writ3 ;:yes
test al,21h ;error ?
jnz hd_writ8
loop hd_writ2
mov al,80h ;time-out
jmp short hd_writ9
hd_writ3: mov dl,low(hdc_dat) ;write 512 bytes from drive
mov cx,256
es: rep outsw
call hd_int ;wait for interrupt
jb hd_writ9
dec bl ;another sector ?
jnz hd_writ1 ;:yes
hd_writ8: call hd_stat ;get status
hd_writ9: jmp hd_exit0
;
; AH=04: verify sectors
;
hd_verify: call hd_sel ;select drive
jb hd_ver9
call hd_chs ;translate CHS
mov al,40h
call hd_cmd ;read verify command
jb hd_ver9
call hd_stat ;get status
hd_ver9: jmp hd_exit0
;
; AH=08: get drive parameters
;
hd_getprm: cmp byte [m_hdcnt],0 ;no drives ?
jnz hd_getp1
jmp hd_badcmd ;:bad command
hd_getp1: call hd_parm ;get ^parameters
mov al,7 ;invalid drive number
mov cx,0 ;return 0 size
mov dx,0
jb hd_getp9 ;:not present
mov dh,[cs:di.dpt_head] ;DH = max head number
dec dh
mov dl,[m_hdcnt] ;DL = number of drives
mov cx,[cs:di.dpt_cyl] ;CX = max cylinders (swapped)
dec cx ;-2 for diag, max cyl
dec cx
cmp cx,1023 ;limit cylinder to 1023
jbe hd_getp2
mov cx,1023
hd_getp2: xchg cl,ch
shl cl,6 ;CL high 6 bits = cylinders high
or cl,[cs:di.dpt_sec] ;CL = number of sectors
mov al,0 ;clear status
hd_getp9: mov [bp._cx],cx ;cylinder count
mov [bp._dx],dx ;number drives, heads
jmp hd_exit0
;
; AH=09: set drive parameters
;
hd_setprm: call hd_sel ;select drive
jb hd_setp9
mov ah,[cs:di.dpt_phd] ;number heads (physical)
dec ah
mov dx,hdc_drv ;set maximum heads
in al,dx
or al,ah
out dx,al
mov al,[cs:di.dpt_psec] ;(physical)
mov dl,low(hdc_cnt) ;sector count
out dx,al
mov al,91h ;set drive parameters
call hd_cmd
jb hd_setp9 ;:error
call hd_stat ;check status
hd_setp9: jmp hd_exit0
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -