📄 disk.asm
字号:
iret
i2F_driver_check:
;
; Installation check
;
mov al,0ffh ; say we are installed
iret
i2F_driver_add:
;
; Add new block device DS:DI
;
push ds
push es
push ds
pop es ; ES:DI -> unit
mov ds,cs:DataSegment
call add_unit
pop es
pop ds
iret
i2F_driver_point:
;
; return DS:DI -> first UDSC_
;
mov ds,cs:DataSegment ; DS -> our data
lds di,ds:udsc_root
iret
;
; Execute DRIVER.SYS request ES:BX
;
i2F_driver_req:
push ds
mov ds,cs:DataSegment
Assume DS:CGROUP
mov ds:req_off,bx ; fill in request pointer
mov ds:req_seg,es ; as if it was local
pop ds
Assume DS:Nothing
push cs:driverTable ; fiddle the table address
jmp DriverFunction ; then go to normal handler
extrn DriverFunction:near
extrn IntDiskTable:word ; = DiskTable
driverTable dw CG:IntDiskTable ; push address of table on
; stack as DriverFunction
; examines it
Int2FHandler endp
Assume DS:CGROUP, SS:Nothing, ES:Nothing
Public DiskTable
DiskTable label word
db 24 ; Last supported function
dw CG:dd_init ; 0-initialize driver
dw CG:dd_medchk ; 1-media change check
dw CG:dd_build_bpb ; 2-build BIOS Parameter Block
dw CG:dd_error ; 3-IOCTL string input
dw CG:dd_input ; 4-input
dw CG:dd_error ; 5-nondestructive input (char only)
dw CG:dd_error ; 6-input status (char only)
dw CG:dd_error ; 7-input flush
dw CG:dd_output ; 8-output
dw CG:dd_output_vfy ; 9-output with verify
dw CG:dd_error ; 10-output status (char only)
dw CG:dd_error ; 11-output flush (char only)
dw CG:dd_error ; 12-IOCTL string output
dw CG:dd_open ; 13-device open
dw CG:dd_close ; 14-device close
dw CG:dd_remchk ; 15-removable media check
dw CG:dd_error ; 16-n/a
dw CG:dd_error ; 17-n/a
dw CG:dd_error ; 18-n/a
dw CG:dd_genioctl ; 19-generic IOCTL
dw CG:dd_error ; 20-n/a
dw CG:dd_error ; 21-n/a
dw CG:dd_error ; 22-n/a
dw CG:dd_getdev ; 23-get logical drive
dw CG:dd_setdev ; 24-set logical drive
driver proc near
point_unit: ; get unit descriptor for work drive
;----------
; On Entry:
; ES:BX -> Request Header
; On Exit:
; AL = logical drive
; ES:DI -> es:UDSC_
; (All other registers preserved)
;
mov al,es:RH_UNIT[bx] ; get the unit number (0=A:, 1=B:, etc)
les di,udsc_root ; ES:DI -> 1st es:UDSC_
point_unit10:
cmp al,es:UDSC_DRIVE[di] ; stop if the logical drive matches
je point_unit20
les di,es:UDSC_NEXT[di]
cmp di,0FFFFh ; else try the next es:UDSC_
jne point_unit10
pop ax ; don't return to the caller
mov ax,RHS_ERROR+1 ; return "invalid unit" error
point_unit20:
ret
add_unit: ; add a new unit to the list
;--------
; On Entry:
; ES:DI -> UDSC to add
; On Exit:
; ES:DI preserved
;
mov al,es:UDSC_DRIVE[di] ; get the logical unit
cmp al,MAXPART ; is it too many ?
jae add_unit40
push ds
mov es:word ptr UDSC_NEXT[di],0FFFFh
; make sure it's terminated
and es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
lea si,udsc_root ; DS:SI -> [first UDSC_]
add_unit10:
cmp ds:word ptr UDSC_NEXT[si],0FFFFh
je add_unit30
lds si,ds:UDSC_NEXT[si] ; DS:SI -> UDSC_ we already have
mov al,es:UDSC_RUNIT[di]
cmp al,ds:UDSC_RUNIT[si] ; do the logical units match ?
jne add_unit10
mov ax,ds:UDSC_FLAGS[si] ; inherit some flags
push ax
and ax,UDF_HARD+UDF_CHGLINE
mov es:UDSC_FLAGS[di],ax ; hard disk/changeline inherited
pop ax
test ax,UDF_HARD
jnz add_unit10 ; skip owner stuff on hard drive
test ax,UDF_VFLOPPY ; is this a multiple drive anyway ?
jnz add_unit20
or ax,UDF_OWNER+UDF_VFLOPPY
mov ds:UDSC_FLAGS[si],ax ; no, 1st person becomes owner
add_unit20:
or es:UDSC_FLAGS[di],UDF_VFLOPPY
jmps add_unit10 ; go and try the next
add_unit30:
mov ds:word ptr UDSC_NEXT[si],di
mov ds:word ptr UDSC_NEXT+2[si],es
pop ds
add_unit40:
ret
dd_error: ; 3-IOCTL string input
;--------
mov ax,RHS_ERROR+3 ; "invalid command" error
ret
dd_medchk: ; 1-media change check
;---------
; entry: ES:BX -> request header
; exit: RH1_RETURN = 0, 1 or FF
; 00 = media may have changed
; 01 = media hasn't changed
; FF = media has been changed
call point_unit ; get unit descriptor
test es:UDSC_FLAGS[di],UDF_HARD
jnz medchk2 ; "hasn't changed" if hard disk
call ask_for_disk ; make sure we've got correct floppy
mov ax,es:UDSC_FLAGS[di] ; get flags
test ax,UDF_UNSURE ; has format/diskcopy occurred?
jnz medchk6 ; may have changed to different format
test ax,UDF_CHGLINE
jz medchk3 ; skip ROS call if no change line
mov dl,es:UDSC_RUNIT[di]
mov al,dl ; don't trust changeline if we are
xchg al,activeRosUnit ; changing floppies
cmp al,dl ; return may have changed
jne medchk3
mov ah,ROS_DSKCHG ; get disk change status function
int_____DISK_INT ; AH=0: DC low, AH=6: DC active
jc medchk5 ; disk change not active?
medchk2:
mov al,01h ; disk hasn't changed
jmps medchk_ret
medchk3: ; no changeline support, use timer
call read_system_ticks ; get system tick count in CX/DX
mov ax,dx
xchg ax,es:UDSC_TIMER[di] ; get previous time and update
sub dx,ax
mov ax,cx
xchg ax,es:UDSC_TIMER+2[di]
sbb cx,ax ; CX/DX = # ticks since last access
jne medchk5 ; media could have changed if > 64k
cmp dx,18*3 ; more than three seconds expired?
jb medchk2 ; "not changed" if access too recent
medchk5:
mov cx,1 ; read track 0, sector 1 (boot sector)
call login_read ; to check the builtin BPB
jc medchk6 ; may have changed if read error
mov al,local_buffer+11+BPB_FATID
cmp al,0F0h ; check if we find a BPB
jb medchk6 ; may have changed if not good BPB
cmp al,es:UDSC_BPB+BPB_FATID[di]
jne medchk8 ; has media byte changed ?
mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
lodsb ; get extended boot
sub al,29h ; do we have an extended boot ?
je medchk7 ; no, test against our dummy value
push cs
pop ds ; DS:SI -> our dummy value
mov si,offset CGROUP:dummyMediaID
medchk7:
push di
lea di,UDSC_SERIAL[di]
mov cx,2
repe cmpsw ; is serial number unchanged ?
pop di
je medchk6 ; then return may have changed
medchk8:
lea ax,UDSC_LABEL[di] ; ES:AX -> ASCII label
lds bx,REQUEST[bp]
mov ds:word ptr RH1_VOLID[bx],ax
mov ds:word ptr RH1_VOLID+2[bx],es
mov al,0FFH ; return disk changed
jmps medchk_ret
medchk6:
mov al,00h ; disk may have changed
medchk_ret:
and es:UDSC_FLAGS[di],not UDF_UNSURE
les bx,REQUEST[bp]
mov es:RH1_RETURN[bx],al ; set return value
sub ax,ax
ret
page
dd_build_bpb: ; 2-build BIOS Parameter Block
;------------
call point_unit ; get unit descriptor
test es:UDSC_FLAGS[di],UDF_HARD
jnz bldbpb1 ; BPB doesn't change for hard disks
call login_media ; try to determine media type (BPB)
jc bldbpb_err
bldbpb1:
mov es:UDSC_OPNCNT[di],0 ; no files open at this time
and es:UDSC_FLAGS[di],not UDF_UNSURE
; media is sure
lea si,UDSC_BPB[di]
mov ax,es
les bx,REQUEST[bp]
mov es:RH2_BPBOFF[bx],si ; return the current BPB
mov es:RH2_BPBSEG[bx],ax
xor ax,ax
ret
bldbpb_err:
jmp xlat_error ; return error code
; ret
login_media: ; determine BPB for new floppy disk
;-----------
push ds
mov cx,1 ; read track 0, sector 1 (boot)
call login_read ; to determine media type
jc login_media_err ; abort if physical error
cmp local_buffer+11+BPB_FATID,0F0h
jb login_media10 ; fail unless FATID sensible
lodsw ; get JMP instruction from boot sector
xchg ax,bx ; save in BX
lodsb ; get next 3rd byte in AX
add si,8 ; skip JMP, OEM name, SI -> BPB
cmp bl,0E9h ; does it start with a JMP ?
je login_media40
cmp bl,069h
je login_media40
cmp bl,0EBh ; how about a JMPS ?
jne login_media10
cmp al,090h ; then we need a NOP
je login_media40
login_media10:
mov cx,2 ; read track 0, sector 2 (FAT)
call login_read ; try to read the sector
jc login_media_err ; abort if physical error
cmp word ptr 1[si],-1 ; bytes 1, 2 must be 0FFh, 0FFh
jne login_media30 ; default media if bad FAT
lodsb ; else get FAT ID byte
mov si,CG:bpb160 ; look through builtin BPB table
mov cx,NBPBS ; # of builtin BPBs
login_media20:
cmp al,BPB_FATID[si] ; does it match one we know?
je login_media40 ; yes, use builtin BPB
add si,BPB_LENGTH ; else move to next BPB
loop login_media20 ; repeat for all BPBs
login_media30: ; can't find that FAT ID
lea si,UDSC_DEVBPB[di] ; use the default type
push es
pop ds ; use BPB at DS:SI ->
login_media40:
push di
lea di,UDSC_BPB[di] ; ES:DI -> unit descriptor (UDSC)
mov cx,UDSC_BPB_LENGTH ; size of a BPB (less reserved stuff)
rep movsb ; copy into unit descriptor
pop di
mov es:UDSC_BPB+BPB_SECSIZ[di],SECSIZE
; mov cx,0
mov es:word ptr (UDSC_BPB+BPB_HIDDEN)[di],cx
mov es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di],cx
cmp si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11
jne login_media50 ; is the BPB from the boot sector ?
; mov ax,ds ; if so then check for media id
; cmp ax,cs:DataSegment ; seg check redundant as UDSC_DEVBPB
; jne login_media50 ; is followed by 7 bytes of zero
lodsw ; skip 2 bytes
lodsb ; now get possible boot signature
cmp al,29h ; is it an extended boot sector ?
je login_media60 ; yes, use it
login_media50:
push cs
pop ds ; DS:SI -> our dummy value
mov si,offset CGROUP:dummyMediaID
login_media60:
call UpdateMediaID ; update UDSC_ with media info
clc
login_media_err:
pop ds
ret
dummyMediaID dd 0 ; serial number 0
db 'NO NAME '
db 'FAT12 '
UpdateMediaID:
;-------------
; On Entry:
; DS:SI -> extended boot record info
; ES:DI -> UDSC_ to update
; On Exit:
; ES:DI preserved
;
push di
xor ax,ax ; AX = a handy zero
lea di,UDSC_SERIAL[di]
movsw
movsw ; copy serial number
pop di
push di
lea di,UDSC_LABEL[di]
mov cx,11
rep movsb ; copy the volume label
stosb ; zero terminate it
pop di
push di
lea di,UDSC_FSTYPE[di]
movsw
movsw
movsw
movsw ; copy the file system type
stosb ; zero terminate it
pop di
ret
login_read:
; entry: CH, CL = cylinder/sector to read
; exit: CY = 1, AH = status if error
; else local_buffer filled in
mov dl,es:UDSC_RUNIT[di] ; DL = ROS drive
mov dh,0 ; DH = head number
login_read_dx: ; read on drive DL, head DH
;------------- ; (entry for hard disk login)
mov P_RETRY[bp],RETRY_MAX ; initialize retry count
logrd1:
push es
mov ax,ROS_READ*256 + 1 ; read one sector from ROS
push ds
pop es ; ES = DS = local segment
mov bx,CG:local_buffer
int_____DISK_INT ; call the ROM BIOS
pop es
jnc logrd3 ; skip if no disk error
push ax
; mov ah,ROS_RESET
xor ax,ax
int_____DISK_INT ; reset the drive
pop ax
dec P_RETRY[bp]
jnz logrd1 ; loop back if more retries
logrd2:
stc
logrd3:
mov si,CG:local_buffer
ret
page
dd_output: ; 8-output
;---------
mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
jmps io_common
dd_output_vfy: ; 9-output with verify
;-------------
mov P_ROSCMD[bp],ROS_VERIFY ; write & verify floppy/hard disk
jmps io_common
dd_input: ; 4-input
;--------
mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
; jmps io_common
io_common: ; common code for the above three
call point_unit ; get unit descriptor
call ask_for_disk ; make sure we've got correct floppy
call setup_rw ; setup for read/write operation
jc io_ret ; return if bad parameters
io_loop:
call track_rw ; read as much as possible on track
jc xlat_error ; return if physical disk error
cmp P_COUNT[bp],0 ; test if any more stuff to read
jne io_loop ; yes, loop back for more
mov al,es:UDSC_RUNIT[di] ; remember the drive that is active
mov activeRosUnit,al
test es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
jnz io_exit ; skip timer read for hard/changeline
call read_system_ticks ; get system tick count in CX/DX
mov es:UDSC_TIMER[di],dx
mov es:UDSC_TIMER+2[di],cx ; save time of successful access
io_exit:
xor ax,ax ; all done, no error encountered
io_ret:
ret
xlat_error: ; translate ROS error to DOS error
;----------
; entry: AH = ROS disk error code, CY = 1
; exit: AX = status to be returned to BDOS
pushx <es, di> ; save some registers
mov al,ah ; AL = ROS error code
push cs
pop es
mov di,CG:ros_errors ; ES:DI -> ROS error code table
mov cx,NUMROSERR
repne scasb ; scan for match
mov ax,RHS_ERROR ; get basic error indication
or al,cs:(CG:dos_errors-CG:ros_errors-1)[di]
; combine with type of error
popx <di, es>
stc
ret
setup_rw: ; prepare for INPUT, OUTPUT or OUTPUT_VFY
;--------
; On Entry:
; ES:DI -> UDSC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -