📄 disk.asm
字号:
; On Exit:
; if CY == 0:
; P_CYL, P_HEAD, P_SECTOR,
; P_DMAOFF, P_DMASEG, P_COUNT initialized
; if CY == 1: invalid parameters detected
; ES:DI preserved
push ds
lds bx,REQUEST[bp]
mov ax,ds:RH4_BUFOFF[bx] ; get offset of transfer buffer
mov P_DMAOFF[bp],ax ; set transfer offset
mov ax,ds:RH4_BUFSEG[bx] ; get segment of transfer buffer
mov P_DMASEG[bp],ax ; set transfer segment
mov ax,ds:RH4_COUNT[bx] ; get sector count from request header
mov P_COUNT[bp],ax ; save it locally for later
mov ax,ds:RH4_SECTOR[bx] ; get low 16 bit of sector #
sub dx,dx ; assume value is 16 bit only
cmp ds:RH_LEN[bx],22 ; check if small request
je setrw2 ; if so forget the rest
cmp ds:RH_LEN[bx],24 ; check if large request
jne setrw1
mov dx,ds:RH4_SECTOR+2[bx] ; yes, get 32-bit record number
jmps setrw2
setrw1:
cmp ds:RH_LEN[bx],30
jne setrw2
cmp ax,-1 ; magic number indicating it's
jne setrw2 ; a 32-bit record number
mov ax,ds:RH4_BIGSECTORLO[bx]
mov dx,ds:RH4_BIGSECTORHI[bx]
setrw2:
pop ds
mov cx,P_COUNT[bp] ; get requested count
jcxz setrw3 ; invalid count
dec cx ; CX = count - 1
cmp es:word ptr (UDSC_BPB+BPB_TOTSEC)[di],0
jne setrw4 ; skip if < 65536 sectors on disk
add ax,cx
adc dx,0 ; AX/DX = # of last sector for I/O
jc setrw3 ; error if > 32 bits
cmp dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
ja setrw3 ; skip if too large
jb setrw5 ; O.K. if small enough
cmp ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
jb setrw5 ; fail if too large
setrw3:
mov ax,RHS_ERROR+8 ; return "sector not found"
stc
ret
setrw4: ; less than 65536 records
add ax,cx ; compute end of transfer
jc setrw3 ; skip if overflow
cmp ax,es:UDSC_BPB+BPB_TOTSEC[di]
jae setrw3 ; skip if too large
setrw5:
sub ax,cx
sbb dx,0 ; add partition address for hard disk
add ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
adc dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
push ax ; AX/DX = 32 bit starting record address
push dx ; save starting record
mov ax,es:UDSC_BPB+BPB_SPT[di]
mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
mov cx,ax ; CX = sectors per cylinder
pop dx ; recover 32 bit start block
pop ax
div cx ; AX = cylinder #, DX = head/sec offset
mov P_CYL[bp],ax ; save physical cylinder number
xor ax,ax ; make remainder 32 bit so
xchg ax,dx ; DX:AX = (head # * SPT) + sector #
div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
mov P_HEAD[bp],al ; save physical sector/head for later
clc ; tell them we like the parameters
ret ; we've figured out starting address
track_rw:
;--------
; entry: P_CYL = cylinder for start of transfer
; P_HEAD = head # for start of transfer
; P_SECTOR = sector # for start of transfer
; P_COUNT = remaining sector count
; P_DMAOFF = transfer offset
; P_DMASEG = transfer segment
; ES:DI -> UDSC structure
; exit: CY = 0 if no error, P_COUNT = remaining sectors
; CY = 1 if error, AH = ROS error code
call track_setup ; compute size of transfer
if FASTSETTLE
call new_settle ; set new head settle delay
endif
cmp P_DIRECT[bp],0 ; DMA boundary problem?
jne trkrw10 ; no, direct transfer performed
cmp P_ROSCMD[bp],ROS_READ
je trkrw10 ; skip if not writing to disk
pushx <ds, es, di>
mov cx,SECSIZE/2 ; CX = # of word per sector
push ds
pop es ; ES:DI -> destination
mov di,CG:local_buffer
lds si,P_DMA[bp] ; DS:SI -> source
rep movsw ; copy from deblocking buffer
popx <di, es, ds>
trkrw10:
mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
trkrw20: ; loop back here for retries
mov cx,P_CYL[bp] ; get cylinder #
xchg cl,ch ; CH = bits 0..7, CL = bits 8..11
ror cl,1
ror cl,1 ; cylinder bits 8..9 in bits 6..7
mov dh,cl ; cylinder bits 10.11 in bits 0..1
and cl,11000000b ; isolate cylinder bits 8..9
add cl,P_SECTOR[bp] ; bits 0..5 are sector number
inc cx ; make it one-relative for ROS
ror dh,1
ror dh,1 ; cylinder bits 10..11 in bits 6..7
and dh,11000000b ; isolate cylinder bits 10..11
add dh,P_HEAD[bp] ; add physical head number
mov dl,es:UDSC_RUNIT[di] ; get ROS unit #
push es
mov ax,ds
mov es,ax
mov bx,CG:local_buffer ; point at our local buffer
cmp P_DIRECT[bp],0 ; DMA boundary problem?
je trkrw30 ; no, direct transfer performed
les bx,P_DMA[bp] ; ES:BX -> transfer address
trkrw30:
mov ax,P_MCNT[bp] ; AL = physical sector count
mov ah,P_ROSCMD[bp] ; AH = ROS read command
cmp ah,ROS_VERIFY ; write with verify?
jne trkrw40 ; skip if ROS_READ or ROS_WRITE
mov ah,ROS_WRITE ; else first perform normal write
int_____DISK_INT ; call ROS to write to disk
jc trkrw50 ; skip if any errors occurred
mov ax,P_MCNT[bp] ; else get sector count
mov ah,ROS_VERIFY ; verify disk sectors
trkrw40: ; AH = function, AL = count
int_____DISK_INT ; read/write/verify via ROM BIOS
trkrw50: ; CY = 1, AH = error code
pop es
jnc trkrw70 ; skip if no errors occurred
call disk_reset ; reset the hardware
cmp ah,11h ; ECC corrected data?
je trkrw60 ; first sector known to be good
cmp ah,03h ; write protect error
je trkrw_error ; don't recover, report to user
dec P_RETRY[bp] ; count # of errors so far
jnz trkrw20 ; retries done, declare it permanent
trkrw_error: ; disk error occurred
if FASTSETTLE
call old_settle ; restore head settle delay
endif
stc ; CY = 1 indicates error, AH = code
ret
trkrw60: ; ECC error, only 1st sector OK
mov P_MCNT[bp],1 ; say we have done one sector
trkrw70: ; read/write/verify succeeded
cmp P_DIRECT[bp],0 ; DMA boundary problem?
jne trkrw80 ; no, direct transfer performed
cmp P_ROSCMD[bp],ROS_READ
jne trkrw80 ; skip if not reading from disk
pushx <di, ds, es>
mov cx,SECSIZE/2 ; CX = # of word per sector
mov si,CG:local_buffer
les di,P_DMA[bp] ; DS:SI -> source, ES:DI -> destination
rep movsw ; copy from deblocking buffer
popx <es, ds, di>
trkrw80:
mov ax,P_MCNT[bp] ; get physical transfer length
sub P_COUNT[bp],ax ; subtract from total transfer length
jz trkrw90 ; exit if none left
add P_SECTOR[bp],al ; update current sector
mov ah,SECSIZE/16
mul ah ; AX = paras to inc DMA address
add P_DMASEG[bp],ax ; update DMA segment
xor ax,ax
mov al,P_SECTOR[bp] ; get current sector
cmp ax,es:UDSC_BPB+BPB_SPT[di]
jb trkrw90 ; skip if on same track
mov P_SECTOR[bp],0 ; else start at beginning of new track
inc P_HEAD[bp] ; move to the next head
mov al,P_HEAD[bp] ; get current head
cmp ax,es:UDSC_BPB+BPB_HEADS[di]
jb trkrw90 ; did we go over end of cylinder?
mov P_HEAD[bp],0 ; start with first head...
inc P_CYL[bp] ; ... on the next cylinder
trkrw90:
if FASTSETTLE
call old_settle ; restore head settle delay
endif
clc ; indicate no errors
ret
disk_reset:
;----------
; entry: DL = ROS drive code
push ax ; save the error status
; mov ah,ROS_RESET ; try a restore
xor ax,ax
int_____DISK_INT ; might sort things out
pop ax ; restore error status
ret
track_setup: ; prepare for I/O on disk track
;-----------
; entry: P_CYL = cylinder for start of transfer
; P_HEAD = head # for start of transfer
; P_SECTOR = sector # for start of transfer
; P_COUNT = remaining sector count
; P_DMAOFF = transfer offset
; P_DMASEG = transfer segment
; ES:DI -> UDSC structure
; exit: P_DIRECT = 1 if no deblocking
; P_MCNT = # of sectors possible in one ROS call
mov ax,P_DMASEG[bp] ; get transfer address
cmp ax,DeblockSeg ; is this in high memory ?
jae trksu20 ; then force through deblock buffer
mov ax,P_COUNT[bp] ; assume we can transfer all
mov P_MCNT[bp],ax ; that's requested this time
mov P_DIRECT[bp],1 ; directly to destination
test es:UDSC_RUNIT[di],80h ; is it a hard disk transfer ?
jnz trksu30 ; yes, transfer the lot
; floppy transfer, break up into tracks
mov dx,es:UDSC_BPB+BPB_SPT[di]
; DX = sectors per track
sub dl,P_SECTOR[bp] ; subtract starting sector
cmp dx,ax ; more than we want?
jae trksu10 ; no, use this count
mov P_MCNT[bp],dx ; set count for this pass
trksu10:
mov ax,P_DMASEG[bp] ; get transfer address
mov cl,4
shl ax,cl ; get A4..A15 from segment
add ax,P_DMAOFF[bp] ; combine with A0..A15 from offset
not ax ; AX = # of bytes left in 64K bank
sub dx,dx
mov cx,SECSIZE
div cx ; convert this to physical sectors
cmp ax,P_MCNT[bp] ; capable of more than requested?
jae trksu30 ; skip if we can do it all
mov P_MCNT[bp],ax ; else update possible transfer length
test ax,ax ; can we transfer anything at all?
jnz trksu30 ; yes, perform the transfer
trksu20:
mov P_MCNT[bp],1 ; single sector transfer via buffer
mov P_DIRECT[bp],0 ; if DIRECT = 0, deblocked transfer
trksu30:
ret
if FASTSETTLE
new_settle:
;----------
test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
jnz new_settle9
cmp P_ROSCMD[bp],ROS_READ
jne new_settle9
push ax
pushx <bx, ds>
sub ax,ax
mov ds,ax
Assume DS:IVECT
lds bx,i1eptr
xchg al,9[bx]
Assume DS:CGROUP
popx <ds, bx>
mov P_SETTLE[bp],al
pop ax
new_settle9:
ret
old_settle:
;----------
test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
jnz old_settle9
cmp P_ROSCMD[bp],ROS_READ
jne old_settle9
pushx <ax, bx, ds>
mov al,P_SETTLE[bp]
sub bx,bx
mov ds,bx
Assume DS:IVECT
lds bx,i1eptr
mov 9[bx],al
Assume DS:CGROUP
popx <ds, bx, ax>
old_settle9:
ret
endif
dd_open: ; 13-device open
;-------
call point_unit ; get unit descriptor
inc es:UDSC_OPNCNT[di] ; increment open count
sub ax,ax
ret
dd_close: ; 14-device close
;--------
call point_unit ; get unit descriptor
dec es:UDSC_OPNCNT[di] ; decrement open count
sub ax,ax
ret
dd_remchk: ; 15-removable media check
;---------
call point_unit ; get unit descriptor
sub ax,ax ; assume floppy disk
test es:UDSC_FLAGS[di],UDF_HARD
jz remchk1 ; skip if it really is a floppy
mov ax,RHS_BUSY ; else return "busy" for hard disk
remchk1:
ret
dd_genioctl: ; 19-generic IOCTL
;-----------
mov cx,es:RH19_CATEGORY[bx] ; get major & minor function
xchg cl,ch ; swap them around
call point_unit ; get unit descriptor
cmp ch,8 ; is it the right major category?
jne ioctl20 ; no, return an error
or es:UDSC_FLAGS[di],UDF_UNSURE
; media unsure after IOCTL
mov si,offset CGROUP:genioctlTable
ioctl10:
lods cs:byte ptr [si] ; get category
mov ch,al ; keep in CH
lods cs:word ptr [si] ; AX = function address
cmp cl,ch ; is it the category we want ?
je ioctl30 ; yes, go do it
test ch,ch ; is it the end of the list ?
jnz ioctl10 ; no, do another one
ioctl20:
mov ax,RHS_ERROR+3 ; "unknown command"
ret
ioctl30:
jmp ax ; go do our routine
genioctlTable label byte
db RQ19_SET ; set device parameters
dw offset CGROUP:ioctl_set
db RQ19_GET ; get device parameters
dw offset CGROUP:ioctl_get
db RQ19_WRITE ; write track
dw offset CGROUP:ioctl_write
db RQ19_READ ; read track
dw offset CGROUP:ioctl_read
db RQ19_FORMAT ; format & verify track
dw offset CGROUP:ioctl_format
db RQ19_VERIFY ; verify track
dw offset CGROUP:ioctl_verify
db RQ19_GETMEDIA ; get media id
dw offset CGROUP:ioctl_getmedia
db RQ19_SETMEDIA ; set media id
dw offset CGROUP:ioctl_setmedia
db 0 ; terminate the list
point_ioctl_packet:
;------------------
; On Entry:
; None
; On Exit:
; DS:BX -> ioctl request packet
; All other regs preserved
;
lds bx,REQUEST[bp]
lds bx,ds:RH19_GENPB[bx] ; ES:BX -> request packet
ret
ioctl_get:
;---------
push ds
call point_ioctl_packet ; DS:BX -> ioctl packet
mov al,es:UDSC_TYPE[di] ; get drive type
mov ds:1[bx],al ; return drive type (0/1/2/5/7)
mov ax,es:UDSC_FLAGS[di] ; get device attributes
and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
mov ds:2[bx],ax ; return device attributes
mov ax,es:UDSC_NCYL[di] ; get # of cylinders
mov ds:4[bx],ax ; return # of cylinders
sub ax,ax ; for now always say "default"
mov ds:6[bx],al ; return media type
test ds:byte ptr [bx],1 ; return default BPB?
pop ds
lea si,UDSC_DEVBPB[di] ; assume we want device BPB
jz get1 ; skip if yes
test es:UDSC_FLAGS[di],UDF_HARD
jnz get1 ; BPB doesn't change for hard disks
call ask_for_disk ; make sure we've got correct floppy
call login_media ; determine floppy disk type
jc get_err ; abort if can't login disk
lea si,es:UDSC_BPB[di] ; get current BPB
get1:
push ds
push es
push di
push es
call point_ioctl_packet ; DS:BX -> ioctl packet
push ds
pop es
lea di,7[bx] ; ES:DI -> BPB in parameter block
pop ds ; DS:SI -> BPB to copy
mov cx,UDSC_BPB_LENGTH
rep movsb ; copy the BPB across to user
pop di
pop es
pop ds
xor ax,ax ; return success
ret
get_err:
jmp xlat_error ; return error code
; ret
ioctl_set: ; set device parameters
;---------
push ds
push es
call point_ioctl_packet ; DS:BX -> ioctl packet
test ds:byte ptr [bx],2 ; ignore all but track layout?
jnz set2 ; yes, skip BPB stuff
mov al,ds:1[bx] ; get new drive type (0/1/2/5/7)
mov es:UDSC_TYPE[di],al ; set drive type
and es:UDSC_FLAGS[di],not (UDF_HARD+UDF_CHGLINE)
mov ax,ds:2[bx] ; get new device attributes
and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
or es:UDSC_FLAGS[di],ax ; combine the settings
mov ax,ds:4[bx] ; get new # of cylinders
mov es:UDSC_NCYL[di],ax ; set # of cylinders
lea ax,UDSC_BPB[di] ; AX -> media BPB in es:UDSC_
test ds:byte ptr [bx],1 ; fix BPB for "build BPB" call?
jnz set1 ; skip if new media BPB only
lea ax,UDSC_DEVBPB[di] ; AX -> device BPB in es:UDSC_
set1:
lea si,7[bx] ; DS:SI -> new BPB from user
xchg ax,di ; ES:DI -> BPB in es:UDSC_
mov cx,UDSC_BPB_LENGTH
rep movsb ; copy BPB into UDSC as new default
xchg ax,di ; ES:DI -> UDSC_ again
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -