home *** CD-ROM | disk | FTP | other *** search
- title XMSDISK XMS-aware RAMdisk
- page 55,132
-
- ; XMSDISK.ASM --- XMS-aware RAMdisk device driver
- ; Copyright (C) 1989 Ziff Davis Communications
- ; PC Magazine * Ray Duncan
- ; Also requires ITOA.ASM and ATOI.ASM.
- ;
- ; To build: MASM XMSDISK;
- ; MASM ATOI;
- ; MASM ITOA;
- ; LINK XMSDISK+ATOI+ITOA;
- ; EXE2BIN XMSDISK.EXE XMSDISK.BIN
- ; DEL XMSDISK.EXE
- ;
- ; To install: copy XMSDISK.SYS to the boot disk, add
- ;
- ; DEVICE=XMSDISK.BIN nnnK
- ;
- ; to the CONFIG.SYS file. This must follow
- ; the DEVICE= line that loads the XMM (usually
- ; HIMEM.SYS). The parameter nnn is the desired
- ; RAMdisk size in KB. If nnn is missing or zero,
- ; all available extended memory is used.
- ;
- _TEXT segment public 'CODE'
-
- extrn atoi:near
- extrn itoa:near
-
- assume cs:_TEXT,ds:_TEXT,es:NOTHING
-
- org 0
-
- maxcmd equ 24 ; maximum driver command code
-
- cr equ 0dh ; ASCII carriage return
- lf equ 0ah ; ASCII line feed
- blank equ 020h ; ASCII space code
- eom equ '$' ; end of message indicator
-
- secsize equ 512 ; bytes per sector (IBM standard)
- dirsize equ 256 ; entries in root directory
-
- request struc ; request packet template
- len db ? ; length of request packet
- unit db ? ; unit number for this request
- command db ? ; request packet's command code
- status dw ? ; status returned by driver
- db 8 dup (?) ; reserved area
- media db ? ; media descriptor byte
- address dd ? ; memory address for transfer
- count dw ? ; byte/sector count value
- sector dw ? ; starting sector value
- request ends ; end of request packet template
-
- header equ $ ; device driver header
- dd -1 ; link to next driver
- dw 0 ; device attribute word
- dw strat ; device "Strategy" entry point
- dw intr ; device "Interrupt" entry point
- db 1 ; number of units, this device
- db 7 dup (0) ; reserved (block drivers)
-
- rqptr dd ? ; far pointer to request packet
- savesp dw 0 ; save kernel SS:SP during switch
- savess dw 0 ; to driver's private stack
- xmm dd 0 ; address of XMM entry point
- handle dw 0 ; handle for extended memory block
- total dw 0 ; total extended mem available (KB)
- largest dw 0 ; largest free block available (KB)
- alloc dw 0 ; extended memory allocated (KB)
- clust dw 0 ; total clusters in RAMdisk
- xfersec dw 0 ; current sector for transfer
- xfercnt dw 0 ; sectors successfully transferred
- xferreq dw 0 ; number of sectors requested
-
- array dw bpb ; array of pointers to BPBs
- ; for each logical unit
-
- movpars equ $ ; XMS Function 0BH parameter block
- movelen dd 0 ; length to move in bytes
- shandle dw 0 ; source handle
- soffset dd 0 ; source offset or far pointer
- dhandle dw 0 ; destination handle
- doffset dd 0 ; destination offset or far pointer
-
- bootrec equ $ ; boot record for logical sec. 0
- jmp $ ; phony JMP at start of boot
- nop ; sector (must be 3 bytes)
- db 'IBM 3.3' ; OEM identity field
- ; BIOS Parameter Block (BPB)
- bpb dw secsize ; 0 bytes per sector
- db 2 ; 2 sectors per cluster
- dw 1 ; 3 reserved sectors
- db 1 ; 5 number of FATs
- dw dirsize ; 6 root directory entries
- dw 0 ; 8 total sectors
- db 0f8h ; 0AH medium descriptor byte
- dw 0 ; 0BH sectors per FAT
- bootrec_len equ $-bootrec ; length of boot record
-
- even ; force word alignment
- dw 128 dup (0)
- stk equ $ ; local stack for driver
-
- ;
- ; Driver 'strategy' routine; called by MS-DOS kernel with
- ; ES:BX pointing to driver request packet.
- ;
- strat proc far ; driver 'strategy' routine
-
- mov word ptr cs:rqptr,bx ; save request packet address
- mov word ptr cs:rqptr+2,es
- ret ; back to MS-DOS kernel
-
- strat endp
-
- ;
- ; Driver 'interrupt' routine, called by MS-DOS kernel immediately
- ; after call to 'strategy' routine to process I/O request.
- ;
- intr proc far
-
- push ax ; save all registers
- push bx
- push cx
- push dx
- push ds
- push es
- push di
- push si
- push bp
-
- mov ax,cs ; make local data addressable
- mov ds,ax
- mov savess,ss ; save DOS kernel's stack
- mov savesp,sp
- mov ss,ax ; set SS:SP to point to
- mov sp,offset stk ; (larger) local stack
-
- les di,rqptr ; ES:DI = request packet
- mov bl,es:[di.command] ; get BX = command code
- xor bh,bh
- cmp bx,maxcmd ; make sure it's legal
- jle intr1 ; jump, function code is ok
- mov ax,8003h ; return 'unknown command' error
- jmp intr2
-
- intr1: shl bx,1 ; branch to command code routine
- call word ptr [bx+dispch] ; must return AX = status
- les di,rqptr ; ES:DI = request packet again
-
- intr2: or ax,0100h ; merge 'done' bit into status
- mov es:[di.status],ax ; store into request packet
-
- mov ss,savess ; restore DOS kernel's stack
- mov sp,savesp
-
- pop bp ; restore general registers
- pop si
- pop di
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- ret ; back to kernel
-
- intr endp
-
- ;
- ; Dispatch table for driver commands
- ;
- dispch dw init ; 0 = initialize driver
- dw medchk ; 1 = media check on block device
- dw bldbpb ; 2 = build BIOS parameter block
- dw error ; 3 = I/O control read
- dw read ; 4 = read from device
- dw error ; 5 = non-destructive read
- dw error ; 6 = return current input status
- dw error ; 7 = flush device input buffers
- dw write ; 8 = write to device
- dw write ; 9 = write with verify
- dw error ; 10 = return current output status
- dw error ; 11 = flush output buffers
- dw error ; 12 = I/O control write
- dw error ; 13 = device open (DOS 3.0+)
- dw error ; 14 = device close (DOS 3.0+)
- dw error ; 15 = removeable media (DOS 3.0+)
- dw error ; 16 = output until busy (DOS 3.0+)
- dw error ; 17 = not used
- dw error ; 18 = not used
- dw error ; 19 = generic IOCTL (DOS 3.2+)
- dw error ; 20 = not used
- dw error ; 21 = not used
- dw error ; 22 = not used
- dw error ; 23 = get logical device (DOS 3.2+)
- dw error ; 24 = set logical device (DOS 3.2+)
-
- ;
- ; Media Check routine (command code 1). Returns code indicating
- ; whether medium has been changed since last access.
- ;
- medchk proc near
-
- mov byte ptr es:[di+14],1 ; return "not changed" code
- xor ax,ax ; return success status
- ret
-
- medchk endp
-
- ;
- ; Build BPB routine (command code 2). Returns pointer to valid
- ; BIOS Parameter Block for logical drive.
- ;
- bldbpb proc near
-
- mov word ptr es:[di+20],cs ; put BPB address in packet
- mov word ptr es:[di+18],offset bpb
- xor ax,ax ; return success status
- ret
-
- bldbpb endp
-
- ;
- ; Read routine (command code 4). Transfers logical sector(s)
- ; from RAMdisk storage to specified address.
- ;
- read proc near
-
- mov ax,es:[di.sector] ; ES:DI = request packet
- mov xfersec,ax ; save starting sector number
- mov ax,es:[di.count]
- mov xferreq,ax ; save sectors requested
- mov xfercnt,0 ; init sectors transferred count
- mov ax,word ptr es:[di.address]
- mov word ptr doffset,ax ; requestor's buffer address
- mov ax,word ptr es:[di.address+2]
- mov word ptr doffset+2,ax
- mov ax,handle ; source handle = extended
- mov shandle,ax ; memory handle
- mov dhandle,0 ; destination handle = 0
- mov word ptr movelen,secsize; logical sector length
-
- read1: mov ax,xfercnt ; done with all sectors yet?
- cmp ax,xferreq
- je read2 ; jump if transfer completed
-
- mov ax,xfersec ; source offset =
- mul bpb ; sector no. * bytes/sector
- mov word ptr soffset,ax
- mov word ptr soffset+2,dx
-
- mov ah,0bh ; move this sector from
- mov si,offset movpars ; extended memory to requestor
- call xmm
- or ax,ax ; any error?
- jz read4 ; yes, abort transfer
-
- inc xfersec ; advance sector and address
- add word ptr doffset+2,(secsize/16)
- inc xfercnt ; count sectors transferred
- jmp read1
-
- read2: ; all sectors transferred,
- xor ax,ax ; return success status
-
- read3: les di,rqptr ; get address of request packet
- mov bx,xfercnt ; return sectors transferred count
- mov es:[di.count],bx
- ret
-
- read4: mov ax,800bh ; XMM error, return 'read fault'
- jmp read3
-
- read endp
-
- ;
- ; Write (command code 8) and Write with Verify (command code 9)
- ; routine. Transfers logical sector(s) from specified address
- ; to RAMdisk storage.
- ;
- write proc near
-
- mov ax,es:[di.sector] ; ES:DI = request packet
- mov xfersec,ax ; save starting sector number
- mov ax,es:[di.count]
- mov xferreq,ax ; save sectors requested
- mov xfercnt,0 ; init sectors transferred count
- mov ax,word ptr es:[di.address]
- mov word ptr soffset,ax ; requestor's buffer address
- mov ax,word ptr es:[di.address+2]
- mov word ptr soffset+2,ax
- mov ax,handle ; destination handle = extended
- mov dhandle,ax ; memory handle
- mov shandle,0 ; zero out source handle
- mov word ptr movelen,secsize; logical sector length
-
- write1: mov ax,xfercnt ; done with all sectors yet?
- cmp ax,xferreq
- je write2 ; jump if transfer completed
-
- mov ax,xfersec ; destination offset =
- mul bpb ; sector no. * bytes/sector
- mov word ptr doffset,ax
- mov word ptr doffset+2,dx
-
- mov ah,0bh ; move this sector from
- mov si,offset movpars ; requestor to extended memory
- call xmm
- or ax,ax ; any error?
- jz write4 ; yes, abort transfer
-
- inc xfersec ; advance sector and address
- add word ptr soffset+2,(secsize/16)
- inc xfercnt ; count sectors transferred
- jmp write1
-
- write2: ; all sectors successfully
- xor ax,ax ; transferred, return ok status
-
- write3:
- les di,rqptr ; get address of request packet
- mov bx,xfercnt ; return actual transfer count
- mov es:[di.count],bx
- ret
-
- write4: mov ax,800ah ; XMM error, return 'write fault'
- jmp write3
-
- write endp
-
- ;
- ; Dummy routine for unsupported driver command codes
- ;
- error proc near
-
- mov ax,8103h ; return 'unknown command' error
- ret
-
- error endp
-
- ;
- ; Initialization routine, called at driver load time. Returns
- ; address of 'init' label to MS-DOS as start of free memory, so
- ; that memory occupied by 'init' and its subroutines is reclaimed.
- ;
- init proc near ; command code 0 = initialize
-
- mov ax,4300h ; check if XMM present
- int 2fh
- cmp al,80h ; status = installed?
- je init1 ; yes, proceed
- mov dx,offset msg1 ; no, display error message
- jmp init8 ; and abort installation
-
- init1: mov ax,4310h ; XMM available, request entry
- int 2fh ; point and save it
- mov word ptr xmm,bx
- mov word ptr xmm+2,es
-
- mov ah,8 ; get available extended memory
- call xmm ; transfer to XMM
- mov total,dx ; save total KB available
- mov largest,ax ; save largest free block
- cmp largest,64 ; at least 64 KB available?
- jae init2 ; yes, proceed
- mov dx,offset msg2 ; no, display error message
- jmp init8 ; and abort installation
-
- init2: les di,rqptr ; let ES:DI = request packet
- lds si,es:[di+18] ; point to CONFIG.SYS line
-
- init3: lodsb ; scan for end of driver name
- cmp al,blank
- ja init3 ; loop while within name
- dec si ; point to delimiter and
- call atoi ; convert size parameter
- push cs ; make our data addressable
- pop ds
- or ax,ax ; size parameter missing?
- jz init4 ; yes, use all extended memory
- cmp ax,largest ; requested > available?
- jna init5 ; no, jump
-
- init4: mov ax,largest ; use all of available memory
-
- init5: mov alloc,ax ; save requested size
- mov dx,ax ; DX = RAMdisk size in KB
- mov ah,9 ; XMS function 9 = allocate
- call xmm ; transfer to XMM
- or ax,ax ; allocation successful?
- jnz init6 ; yes, proceed
- mov dx,offset msg3 ; no, display error message
- jmp init8 ; and abort installation
-
- init6: mov handle,dx ; save extended memory handle
- call makebpb ; set up Bios Parameter Block
- call format ; format the RAMdisk
- jnc init7 ; jump if no error during format
- mov dx,offset msg4 ; formatting error, exit
- jmp init8
-
- init7: les di,rqptr ; let ES:DI = request packet
- mov al,es:[di+22] ; get drive code from header,
- add al,'A' ; convert to ASCII for output
- mov ident1,al
- mov ax,total ; convert KB available to ASCII
- mov si,offset ident2
- mov cx,10
- call itoa
- mov ax,largest ; convert KB largest free block
- mov si,offset ident3
- call itoa
- mov ax,alloc ; convert KB allocated to ASCII
- mov si,offset ident4
- call itoa
-
- mov dx,offset ident ; display sign-on message
- mov ah,9 ; function 9 = display string
- int 21h ; transfer to MS-DOS
-
- ; set top of driver address
- mov word ptr es:[di.address],offset init
- mov word ptr es:[di.address+2],cs
- mov byte ptr es:[di+13],1 ; indicate 1 logical unit
- mov word ptr es:[di+20],cs ; return address of BPB array
- mov word ptr es:[di+18],offset array
- jmp init9
-
- init8: ; XMSDISK initialization failed
- push dx ; save specific error message
- mov dx,offset errmsg ; display error heading
- mov ah,9 ; function 9 = display string
- int 21h ; transfer to MS-DOS
- pop dx ; display error description
- mov ah,9 ; function 9 = display string
- int 21h ; transfer to MS-DOS
-
- les di,cs:rqptr ; let ES:DI=request packet
- ; set driver end = driver start
- mov word ptr es:[di.address],0
- mov word ptr es:[di.address+2],cs
- mov byte ptr es:[di+13],0 ; set no. of logical units = 0
-
- init9: xor ax,ax ; return success status
- ret
-
- init endp
-
- ;
- ; Set up total sectors and sectors per FAT fields of BIOS Parameter
- ; Block according to size of RAMdisk. Calculate and save total
- ; clusters (indicates whether 12-bit or 16-bit FAT will be used).
- ;
- makebpb proc near
-
- mov ax,alloc ; get size of allocated block
- mov dx,1024 ; convert KB to bytes
- mul dx ; divided by bytes/sector
- div word ptr bpb ; gives AX = total sectors
- mov bpb+8,ax ; update BPB with total sectors
- xor dx,dx ; sectors / (sectors/cluster)
- xor ch,ch ; = total clusters
- mov cl,byte ptr bpb+2
- div cx
- mov clust,ax ; save total clusters
- cmp ax,4086 ; clusters < 4087?
- jna makeb1 ; yes, jump
- shl ax,1 ; no, assume 16-bit FAT
- jmp makeb2 ; clusters * 2 = bytes/FAT
-
- makeb1: mov dx,ax ; if clusters < 4087, 12-bit FAT
- add ax,ax ; clusters * 1.5 = bytes/FAT
- add ax,dx
- shr ax,1
- jnc makeb2
- inc ax ; round bytes up if necessary
-
- makeb2: xor dx,dx ; (bytes/FAT) / (bytes/sec)
- div word ptr bpb ; = sectors/FAT
- or dx,dx ; any remainder?
- jz makeb3 ; no,jump
- inc ax ; round up to next sector
-
- makeb3: mov bpb+0bh,ax ; update FAT size in BPB
- ret
-
- makebpb endp
-
- ;
- ; Format RAMdisk. First write zeros into all sectors of reserved
- ; area, FAT, and root directory. Then copy phony boot record to
- ; boot sector, initialize medium ID byte at beginning of FAT, and
- ; place phony volume label in first sector of root directory.
- ;
- format proc near
-
- push ds ; initialize sector buffer
- pop es ; to zeros so we can clear
- mov di,offset secbuf ; out reserved area, FAT,
- mov cx,secsize ; and root directory
- xor al,al
- rep stosb
-
- mov ax,bpb+6 ; no. of directory entries
- mov cx,32 ; * (32 bytes/entry)
- mul cx ; = bytes in root directory
- div bpb ; / (bytes/sector)
- or dx,dx ; = sectors in root directory
- jz fmt1
- inc ax ; round up any partial sector
-
- fmt1: add ax,bpb+3 ; + reserved sectors
- add ax,bpb+0bh ; + sectors in FAT
- mov xferreq,ax ; = total sectors to clear
- mov xfercnt,0 ; initialize sector counter
-
- ; set up move parameter block
- mov word ptr movelen,secsize; length to move
- mov shandle,0 ; source handle and address
- mov word ptr soffset,offset secbuf
- mov word ptr soffset+2,cs
- mov ax,handle ; destination extended memory
- mov dhandle,ax ; block handle
- mov word ptr doffset,0 ; initial destination offset
- mov word ptr doffset+2,0
-
- fmt2: mov ah,0bh ; write this sector
- mov si,offset movpars ; DS:SI = parameter block
- call xmm ; transfer to XMM
- or ax,ax ; test move status
- jnz fmt3
- jmp fmt5 ; abort if move failed
-
- fmt3: add word ptr doffset,secsize; increment destination address
- adc word ptr doffset+2,0
- mov ax,xfercnt ; count sectors initialized
- inc ax
- mov xfercnt,ax
- cmp ax,xferreq ; done yet?
- jne fmt2 ; not done, write another
-
- mov ax,bpb+3 ; calculate offset of first
- mul bpb ; FAT sector in RAMdisk buffer
- mov word ptr doffset,ax ; set destination address
- mov word ptr doffset+2,dx
-
- mov al,byte ptr bpb+0ah ; set up medium ID byte
- mov secbuf,al ; in first FAT sector
- mov word ptr secbuf+1,-1 ; assume 12-bit FAT
- cmp clust,4086 ; more than 4086 clusters?
- jna fmt4 ; no, jump
- mov secbuf+3,0ffh ; yes, use 16-bit FAT
-
- fmt4: mov ah,0bh ; write first FAT sector
- mov si,offset movpars
- call xmm
- or ax,ax ; test move status
- jz fmt5 ; abort if move failed
-
- mov word ptr doffset,0 ; offset of logical sector 0
- mov word ptr doffset+2,0
- mov word ptr soffset,offset bootrec
- mov word ptr movelen,bootrec_len
- mov ah,0bh ; copy phony boot record
- mov si,offset movpars ; to logical sector 0
- call xmm
- or ax,ax ; test move status
- jz fmt5 ; abort if move failed
-
- mov ax,bpb+0bh ; calculate offset of first
- add ax,bpb+3 ; root directory sector
- mul bpb ; in RAMdisk buffer
- mov word ptr doffset,ax
- mov word ptr doffset+2,dx
- mov word ptr soffset,offset volname
- mov word ptr movelen,volname_len
- mov ah,0bh ; copy phony volume label
- mov si,offset movpars ; to first directory sector
- call xmm
- or ax,ax ; test move status
- jz fmt5 ; abort if move failed
-
- clc ; successful format,
- ret ; return CY = clear
-
- fmt5: stc ; format failed,
- ret ; return CY = set
-
- format endp
-
- ;
- ; Miscellaneous data used during initialization, then discarded.
- ;
- ident db cr,lf,lf ; sign-on message
- db 'XMSDISK Extended Memory RAMdisk'
- db cr,lf
- db 'Copyright (C) 1989 Ziff Davis Communications'
- db cr,lf
- db 'PC Magazine * Ray Duncan'
- db cr,lf,lf
- db 'XMSDISK will be drive '
- ident1 db 'X:',cr,lf
- db 'Extended memory available:'
- ident2 db ' KB',cr,lf
- db 'Largest free memory block:'
- ident3 db ' KB',cr,lf
- db 'Extended memory allocated:'
- ident4 db ' KB',cr,lf,eom
-
- errmsg db cr,lf
- db 'XMSDISK installation error:'
- db cr,lf,eom
-
- msg1 db 'Extended Memory Manager not found.'
- db cr,lf,eom
-
- msg2 db 'Insufficient extended memory available.'
- db cr,lf,eom
-
- msg3 db 'Extended memory allocation failed.'
- db cr,lf,eom
-
- msg4 db 'Unable to format RAMdisk.'
- db cr,lf,eom
-
- volname db 'XMSDISK ' ; phony volume label
- db 08h ; volume label attribute byte
- db 10 dup (0)
- dw 0 ; time = 00:00:00
- dw 1241h ; date = February 1, 1989
- db 6 dup (0)
- volname_len equ $-volname
-
- secbuf db secsize dup (?) ; sector buffer for format
-
- _TEXT ends
-
- end
-
-