home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
util4
/
adjram31.lzh
/
AMDISK31.ASM
< prev
Wrap
Assembly Source File
|
1986-10-02
|
21KB
|
674 lines
; ==== Adjustable Memory Disk Device Driver ====
;
; (c) Copyright 1986 by Gary R. Cramblitt
;
; v2.2 1 Jul 86 Initial version
; v2.3 24 Aug 86 Bug. FAT media byte not updated properly
; v2.4 29 Aug 86 Sync version # with ADJRAM.C No other changes.
; v2.5 30 Aug 86 Add /E (LOTUS/INTEL,Microsoft Expanded Memory) support;
; Increase root directory to 128 entries;
; Permit maximum size of 2043K.
; Get rid of second FAT.
; v3.0 5 Sep 86 Sync version # with ADJRAM.C. No other changes.
; v3.1 2 Oct 86 Sync version # with ADJRAM.C. No other changes.
;
; ==== Constant Definition ===================
;
; ---- Customizable Definitions -----
; If these are changed, the corresponding symbols in adjram.c
; must be altered.
min_size_K equ 64 ; minimum 64K ram disk
max_size_K equ 2043 ; maximum 2043K ram disk
sec_per_blk equ 64 ; 32K increments
bytes_per_sec equ 512 ; bytes per sector
sec_per_cl equ 1 ; sectors per cluster
par_per_sec_lg2 equ 5 ; 16-byte paragraphs per sector
; log 2. Must match bytes_per_sec
fats_per_disk equ 1 ; number of FATS
; ---- Derived quantities ----
sec_per_K equ 1024/bytes_per_sec ; sectors per 1024 bytes
par_per_sec equ bytes_per_sec/16 ; 16-byte paragraphs per sector
min_size_sec equ min_size_K*sec_per_K ; min size of disk in sectors
max_size_sec equ max_size_K*sec_per_K ; max size of disk in sectors
bytes_per_fat equ max_size_sec/sec_per_cl*3/2
sec_per_fat equ (bytes_per_fat+bytes_per_sec-1)/bytes_per_sec
K_per_blk equ sec_per_blk/sec_per_K
em_pag_per_mem_blk equ K_per_blk/16 ; EM pages per memory block
; ---- Request Header Structure Definitions ----
rh_length equ 0 ; (byte) length field
rh_unit equ 1 + rh_length ; (byte) unit field
rh_command equ 1 + rh_unit ; (byte) command code
rh_status equ 1 + rh_command ; (word) status field
rh_reserved equ 2 + rh_status ; (8 bytes)
rh_size equ 8 + rh_reserved ; request header size
; ---- Request Header Status values ----
s_done equ 0100h ; done, no errors
s_busy equ 0200h ; busy, no errors
e_err equ 8000h
e_protect equ e_err+0h ; error: write protect
e_unknown_unit equ e_err+1h ; error: unknown unit
e_not_ready equ e_err+2h ; error: not ready
e_command equ e_err+3h ; error: unknown command
e_crc equ e_err+4h ; error: bad CRC
e_bad_length equ e_err+5h ; error: bad structure length
e_seek equ e_err+6h ; error: bad seek
e_media equ e_err+7h ; error: unknown media
e_not_found equ e_err+8h ; error: sector not found
e_paper equ e_err+9h ; error: out of paper
e_write equ e_err+ah ; error: write fault
e_read equ e_err+bh ; error: read fault
e_general equ e_err+ch ; error: general error not listed above
; ---- Non-destructive read parameter block ----
rh_read_data equ rh_size ; (byte) non-destructive data
; ---- Input/output parameter block ----
rh_media equ 0 + rh_size ; (byte) media descriptor
rh_buf_offset equ 1 + rh_media ; (word) transfer buffer offset
rh_buf_segment equ 2 + rh_buf_offset ; (word) transfer buffer segment
rh_buf_size equ 2 + rh_buf_segment ; (word) transfer buffer size
rh_start equ 2 + rh_buf_size ; (word) transfer starting sector
m_fized equ 0f8h ; media: fixed disk
m_ss9 equ 0fch ; media: single sided, 8 sectors/track
m_ds9 equ 0fdh
m_ss8 equ 0feh
m_ds8 equ 0ffh
; ---- Build BPB parameter block ----
; preceeded by media descriptor
rh_bpb equ 1 + rh_media ; (dword) bpb buffer address
rh_tbl_offset equ 4 + rh_bpb ; (dword) bpb table offset/segment
rh_tbl_segment equ 2 + rh_tbl_offset
; ---- Media Check parameter block ----
rh_check equ 1 + rh_media ; (byte) media check result
mc_changed equ -1 ; media has changed
mc_maybe equ 0 ; media may have been changed
mc_same equ 1 ; media has not changed
; ---- Initialize parameter block ----
rh_units equ 0 + rh_size ; (byte) number of units supported
rh_end_offset equ 1 + rh_units ; (word) end address of driver
rh_end_segment equ 2 + rh_end_offset
rh_bpb_offset equ 2 + rh_end_segment ; (word) BPB array address
rh_bpb_segment equ 2 + rh_bpb_offset
; ---- DOS interrupts ----
dosi_dosf equ 21h ; DOS function dispatcher
; ---- User Interrupts ----
usri_emm equ 67h ; Expanded Memory Manager
; ---- DOS interrupt 21 functions ----
dosf_outstr equ 9 ; display string
dosf_seldisk equ 0eh ; select disk
dosf_getdisk equ 19h ; get current disk
; ---- LOTUS/INTEL/Microsoft Expanded Memory Manager functions ----
emm_status equ 40h ; get manager status
emm_get_PFseg equ 41h ; get page frame segment
emm_get_pages equ 42h ; get number of pages
emm_get_handle equ 43h ; get handle and allocate memory
emm_map_memory equ 44h ; map memory
emm_fre_handle equ 45h ; free handle and memory
emm_get_ver equ 46h ; get EMM version
emm_sav_map equ 47h ; save mapping context
emm_res_map equ 48h ; restore mapping context
emm_num_handles equ 4bh ; get number of EMM handles
emm_hdl_pages equ 4ch ; get pages owned by handle
emm_all_pages equ 4dh ; get pages for all handles
emm_pag_map equ 4eh ; get or set page map
; ---- Device Driver Header Attribute Definitions ----
a_input equ 0001h ; standard input device
a_output equ 0002h ; standard output device
a_nul equ 0004h ; NUL device
a_clock equ 0008h ; CLOCK$ device
a_dos equ 0 ; DOS block device (bit 13)
a_not_dos equ 2000h ; non-DOS block device (bit 13)
a_ioctl equ 4000h ; IOCTL functions supported
a_block equ 0 ; block device (bit 15)
a_character equ 8000h ; character device (bit 15)
; ==== Device Driver Header Definition ====
cseg segment para public 'CODE'
driver proc far
assume cs:cseg,ds:cseg,es:cseg
dd -1 ; last driver in chain
dw a_block + a_dos ; driver attribute
dw dev_strategy ; offset to strategy routine
dw dev_interrupt ; offset to interrupt routine
db 1 ; number of devices or device name
db 7 dup ( ? ) ; filler for block device
; ==== Device Driver Tables ====
;
; ---- BIOS Parameter Block Table and Entries ----
bpb_table dw bpb ; one entry for each unit
; ---- Request Header Address set by dev_strategy ----
rh_address dd 1 dup ( ? ) ; request header base address
rh_offset equ word ptr rh_address
rh_segment equ word ptr rh_address + 2
; ---- Request Header Command Dispatch Table ----
cmd_table dw initialize ; initialize driver
dw media_check ; media check
dw build_bpb ; build BPB
dw ioctl_read ; IOCTL read
dw read ; normal read
dw check_input ; non-destructive read/status
dw input_status ; input status
dw input_flush ; flush input buffers
dw write ; normal write
dw write_verify ; normal write with read verify
dw output_status ; output status
dw output_flush ; flush output buffer
dw ioctl_write ; IOCTL write
; ==== Common Device Driver Routines ====
;
; ---- Device Driver Strategy Routine ----
;
; es:bs == request header address
dev_strategy proc far
mov cs:rh_offset,bx
mov cs:rh_segment,es
ret
dev_strategy endp
; ---- Device Driver Interrupt Routine ----
dev_interrupt proc far
push ax ; save registers used
push bx
push cx
push dx
push di
push si
push ds
push es
cld ; clear direction flag
push cs ; setup small memory model
pop ds ; ds := program segment
les bx,rh_address ; es:bs := request header index
mov si,es:rh_command[bx] ; si := request command (byte)
and si,0ffh ; si := request command
add si,si ; si := word table offset
call word ptr cmd_table[si] ; ax := command result
lds bx,cs:rh_address ; ds:bx := request header index
mov rh_status[bx],ax ; update request status
pop es ; restore register
pop ds
pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret
dev_interrupt endp
; **** END OF DEVICE INDEPENDENT PORTION OF DRIVER ****
; ---- Memory Block Table that follows BPB in boot sector ----
mem_blk_table_entry struc
typ db ? ; 0 = normal 1 = Expanded Memory
par dw ? ; paragraph address of block
siz dw ? ; number of sectors in the memory block
hdl dw ? ; EM handle for the block
mem_blk_table_entry ends
nor_flg equ 0 ; Memory Block is in normal memory
em_flg equ 1 ; Memory Block is in expanded memory
; ---- Flag indicating whether expanded memory mapping context has been
; saved yet or not. If nonzero, it indicates that the context has
; been saved.
em_context_flg db 0 ; 0 = not saved; 1 = context saved
em_context_hdl dw ? ; EM handle underwhich context saved
; ==== Memory Disk Device Driver Code ====
;
; ---- Driver support functions (near functions) ----
;
; es:bx == request header
; ds == cs
; All other registers are usable.
;
; ax := result status
;
; ---- Initialize driver ----
initialize proc near ; initialize driver
lea ax,word ptr mdisk_data ; ax := end of driver
mov cl,4 ; cl := paragraph size log2
shr ax,cl ; ax := paragraphs in driver
mov dx,cs ; dx := driver segment
add ax,dx ; ax := memory disk segment
mov mem_blk_table.par,ax ; update for subsequent transfers
mov ax,cs
mov es,ax
lea di,word ptr fat1 ; es:di := first FAT
mov cx,sec_per_fat*bytes_per_sec ; cx = size
push di ; save first FAT address
push es
mov al,cs:bpb_media ; al := media byte
mov [di],al ; update FAT media byte
mov word ptr 1[di],0ffffh ; allocate initial sectors
add di,3 ; adjust FAT index
sub cx,3 ; adjust FAT size
xor al,al ; al := 0
rep stosb ; clear rest of FAT
pop ds
pop si ; ds:si := first FAT index
if fats_per_disk - 1 ; assemble if 2 FATS
lea di,word ptr fat2 ; es:di := second FAT
mov cx,sec_per_fat*bytes_per_sec ; cx := size
rep movsb ; copy first FAT to second FAT
endif
mov ax,cs:bpb_root ; ax := number of directory entries
mov cl,5 ; cl := size of entry log2 (32 bytes)
shl ax,cl ; ax := directory size
mov cx,ax ; cx := directory size
xor al,al ; al := 0
rep stosb ; zero directory
lds bx,cs:rh_address ; ds:bx := request header address
mov byte ptr rh_units[bx],1 ; return number of units
mov word ptr rh_end_offset[bx],offset mdisk_data
mov rh_end_segment[bx],cs ; Calc end address of disk
mov ax,cs:mem_blk_table.siz
mov cl,par_per_sec_lg2
shl ax,cl
add rh_end_segment[bx],ax ; return ending address of driver
mov word ptr rh_bpb_offset[bx],offset bpb_table
mov rh_bpb_segment[bx],cs ; return BPB table address
push cs
pop ds
mov ah,dosf_getdisk ; get current default disk
int dosi_dosf
mov dl,al ; select it
mov ah,dosf_seldisk
int dosi_dosf ; DL := number of drives
add al,'A' ; convert to letter
mov drive,al ; store into message
mov dx,offset initok
mov ah,dosf_outstr
int dosi_dosf
mov ax,s_done ; ax := done, no errors
ret
initok db 10,13,'AMDISK v3.1 (c) Copyright 1986 by Gary Cramblitt'
db '-- Initialized as disk '
drive db ' '
db ':',10,13,'$'
initialize endp
; ---- Media check ----
;
; Memory disk is non-removable media, however, the size of the media
; can be changed. We check the number of 64K memory blocks allocated,
; which is located in the boot record. If it has changed, then the media
; has changed.
media_check proc near ; media check
lds bx,cs:rh_address ; ds:bx := request header address
mov al,cs:bpb_media ; Get our media byte
cmp al,rh_media[bx] ; Changed from what DOS has?
jz media_same ; -- Yes
mov byte ptr rh_check[bx],mc_changed
mov ax,s_done
ret
media_same:
mov byte ptr rh_check[bx],mc_same
mov ax,s_done ; ax := function done, no errors
ret
media_check endp
; ---- Build BPB ----
;
; Read boot sector and copy into BPB buffer
; Adjust request header values
build_bpb proc near ; build BPB
mov al,cs:bpb_media ; al := media byte
lds bx,cs:rh_address ; ds:bx := request header address
mov byte ptr rh_media[bx],al
mov word ptr rh_tbl_offset[bx],offset bpb
mov word ptr rh_tbl_segment[bx],cs
mov ax,s_done ; ax := function done, no errors
ret
build_bpb endp
; ---- Read from device ----
read proc near ; normal read
push es
pop ds ; ds := request header segment
mov di,rh_buf_offset[bx]
mov ax,di
and di,000fh ; di := buffer offset within paragraph
mov cl,4
shr ax,cl
add ax,rh_buf_segment[bx] ; ax := paragraph of buffer
mov es,ax ; es:di := normalized buffer address
mov dx,rh_buf_size[bx] ; dx := sectors to read
mov ax,rh_start[bx] ; ax := first sector to read
mov bx,-(size mem_blk_table_entry) ; find the memory block which..
find_mem_blk_2_read: ; contains the desired sector..
add bx,size mem_blk_table ; by subtracting the # of sectors..
sub ax,cs:mem_blk_table.siz[bx] ; in each block.
jnc find_mem_blk_2_read
add ax,cs:mem_blk_table.siz[bx] ; bx := ptr to memory block table
; ax := sector within the block
push ax ; save sector within block
mov cl,par_per_sec_lg2 ; paragraphs per sector log 2
shl ax,cl ; ax := paragraph within memory block
cmp cs:mem_blk_table.typ[bx],em_flg ; Expanded Memory?
jnz read_set_par
call map_hdl_2_pages ; - Yes, map EM to log mem
read_set_par:
add ax,cs:mem_blk_table.par[bx] ; ax := paragraph in phy mem
mov ds,ax
xor si,si ; ds:si := address of sector
mov cx,cs:mem_blk_table.siz[bx] ; cx := end sector
pop ax ; ax := start sector
sub cx,ax ; cx := secs remaining in mem blk
read_one_sector:
or dx,dx ; All sectors transfered?
jz read_finish ; -- Yes
dec dx
push cx ; save sector count for this blk
mov cx,bytes_per_sec ; 512 bytes per sector
rep movsb ; copy sector to buffer
pop cx ; cx := secs remaining in this blk+1
mov ax,ds
add ax,par_per_sec ; 32 paragraphs per sector
mov ds,ax
xor si,si ; ds:si := address of next sector
mov ax,es ; advance es to next sector
add ax,par_per_sec
mov es,ax
and di,000fh ; es:di := normalized transfer address
loop read_one_sector ; if not end of mem blk, do another
add bx,size mem_blk_table_entry
cmp cs:mem_blk_table.typ[bx],em_flg ; Expanded Memory?
jnz read_set_par_in_loop
call map_hdl_2_pages ; - Yes, map EM to log mem
read_set_par_in_loop:
mov ax,cs:mem_blk_table.par[bx]
mov ds,ax ; ds:si := start of new memory block
mov cx,cs:mem_blk_table.siz[bx] ; cx := size of blk in sectors
jmp read_one_sector
read_finish:
call restore_em_context ; If needed, restore em context
mov ax,s_done ; ax := transfer done
ret
read endp
; ---- Write to device ----
write proc near ; normal write
push es
pop ds ; ds := request header segment
mov dx,rh_buf_size[bx] ; dx := sectors to write
mov si,rh_buf_offset[bx]
mov ax,si
and si,000fh ; si := buffer offset within paragraph
mov cl,4
shr ax,cl
add ax,rh_buf_segment[bx] ; ax := paragraph of buffer
mov cx,ax
mov ax,rh_start[bx] ; ax := first sector to write
mov ds,cx ; ds:si := normalized buffer address
mov bx,-(size mem_blk_table_entry) ; find the memory block which..
find_mem_blk_2_write: ; contains the desired sector..
add bx,size mem_blk_table_entry ; by subtracting the # of sectors..
sub ax,cs:mem_blk_table.siz[bx] ; in each block.
jnc find_mem_blk_2_write
add ax,cs:mem_blk_table.siz[bx]
; bx := ptr to memory block table
; ax := sector within the block
push ax ; save sector within the block
mov cl,par_per_sec_lg2 ; 32 paragraphs per sector log 2
shl ax,cl ; ax := paragraph within memory block
cmp cs:mem_blk_table.typ[bx],em_flg ; Expanded Memory?
jnz write_set_par
call map_hdl_2_pages ; - Yes, map EM
write_set_par:
add ax,cs:mem_blk_table.par[bx] ; ax := paragraph in phy mem
mov es,ax
xor di,di ; es:di := address of sector
mov cx,cs:mem_blk_table.siz[bx] ; cx := size of blk in sectors
pop ax ; ax := start sector within blk
sub cx,ax ; cx := secs remaining in mem blk
write_one_sector:
or dx,dx ; All sectors transfered?
jz write_finish ; -- Yes
dec dx
push cx ; save sector counter
mov cx,bytes_per_sec ; 512 bytes per sector
rep movsb ; copy sector to buffer
pop cx ; cx := secs remaining in blk + 1
mov ax,es
add ax,par_per_sec ; 32 paragraphs per sector
mov es,ax
xor di,di ; es:di := address of next sector
mov ax,ds ; advance ds to next sector
add ax,par_per_sec
mov ds,ax
and si,000fh ; ds:si := normalized transfer address
loop write_one_sector ; if not end of block, do another
add bx,size mem_blk_table_entry
cmp cs:mem_blk_table.typ[bx],em_flg ; Expanded Memory?
jnz write_set_par_in_loop
call map_hdl_2_pages ; - Yes, map EM
write_set_par_in_loop:
mov ax,cs:mem_blk_table.par[bx]
mov es,ax ; es:di := start of new memory block
mov cx,cs:mem_blk_table.siz[bx] ; cx := size of new blk in secs
jmp write_one_sector
write_finish:
call restore_em_context ; If needed, restore em context
mov ax,s_done ; ax := transfer done
ret
write endp
; ---- Write and verify ----
write_verify proc near ; normal write with read verify
jmp write ; assume no errors
write_verify endp
; ==== Support Functions ====
;
; ---- Map a handle of Expanded Memory to the Memory Block pages
; ENTRY: BX = pointer to Memory Block Table entry (in CS)
; EXIT: Memory is mapped and paragraph address updated in entry.
; Flag at CS:em_context_flg is set to nonzero to indicate that
; expanded memory mapping context has been saved. The handle
; underwhich the context was saved is stored at
; CS:em_context_hdl.
; USES: CX
map_hdl_2_pages proc near
push ax
push bx
push dx
mov dx,cs:mem_blk_table.hdl[bx] ; get handle of mem blk
cmp cs:em_context_flg,0 ; em context saved yet?
jnz do_map
mov ah,emm_sav_map ; - No, then save it
int usri_emm
mov cs:em_context_hdl,dx ; store handle underwhich saved
mov cs:em_context_flg,1 ; flag as saved
do_map:
push bx
mov ah,emm_get_PFseg ; get page frame segment
int usri_emm
mov ax,bx
pop bx
mov cs:mem_blk_table.par[bx],ax ; store page frame segment
mov cx,em_pag_per_mem_blk ; # of 16K EM pages to map
map_log_2_phy:
mov ah,emm_map_memory ; map memory
mov al,cl ; physical page number
mov bx,cx ; logical page number
dec al ; adjust relative to 0
dec bx ; adjust relative to 0
int usri_emm
loop map_log_2_phy
pop dx
pop bx
pop ax
ret
map_hdl_2_pages endp
; ---- Restore expanded memory context, if needed. ---
; USES: AX,DX
restore_em_context proc near
cmp cs:em_context_flg,0 ; was context saved?
jz restore_em_context_xit ; - No, then just exit
mov ah,emm_res_map ; - Yes, then restore it..
mov dx,cs:em_context_hdl ; ..using this handle
int usri_emm
mov cs:em_context_flg,0 ; clear context flag
restore_em_context_xit:
ret
restore_em_context endp
; ---- Unimplemented functions ----
unimplemented proc near
mov ax,e_command
ret
unimplemented endp
ioctl_read equ unimplemented ; IOCTL read
check_input equ unimplemented ; non-destructive read/status
input_status equ unimplemented ; input status
input_flush equ unimplemented ; flush input buffers
output_status equ unimplemented ; output status
output_flush equ unimplemented ; flush output buffers
ioctl_write equ unimplemented ; IOCTL write
; ==== Memory Disk Data Area ====
;
; Align to paragraph boundary for easy computation of the sector address
if (( $ - driver) mod 16 )
org ( $ - driver) + (16 - (( $- driver) mod 16 ))
endif
mdisk_data equ $ ; memory disk starts here
; ---- Boot record for initialization ----
boot_record db 3 dup ( 0 ) ; non-bootable (no jump instruction )
db 'AMDISK ' ; identification
bpb: ; BIOS Parameter Block
bytes_in_sector dw bytes_per_sec ; bytes/sector
bpb_sec_per_cl db sec_per_cl ; sectors/cluster
bpb_reserved dw 1 ; reserved sectors
bpb_fats db fats_per_disk ; number of FAT's
bpb_root dw 128 ; directory entries in root
bpb_total dw min_size_sec ; total number of sectors
bpb_media db 1 ; media type byte ...
mem_blk_cnt equ bpb_media ; ...is used for number of mem blocks
bpb_fat_size dw sec_per_fat ; sectors/FAT
dw 1 ; sectors/track
dw 1 ; number of heads
dw 0 ; hidden sectors
mem_blk_table mem_blk_table_entry <nor_flg,,min_size_sec,0> ; memory block table
end_mem_blk_table equ $+(size mem_blk_table)*(max_size_sec/sec_per_blk)
fat1 equ boot_record + bytes_per_sec
fat2 equ fat1 + (bytes_per_sec*sec_per_fat)
root_dir equ fat1+(fats_per_disk*sec_per_fat*bytes_per_sec)
first_data_sec equ root_dir + (64*32)
; ==== End of Memory Disk Device Driver ====
driver endp
cseg ends
end