⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 disk.asm

📁 DOS源码
💻 ASM
📖 第 1 页 / 共 5 页
字号:
; 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 + -