home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1991
/
05
/
tinydosx.asm
< prev
next >
Wrap
Assembly Source File
|
1991-01-31
|
27KB
|
546 lines
title TINYDOSX DPMI-Based Tiny DOS Extender
page 55,132
; TINYDOSX.ASM Tiny DPMI-Based DOS Extender
; Copyright (C) 1990 Ziff Davis Communications
; PC Magazine * Ray Duncan
stdin equ 0 ; standard input handle
stdout equ 1 ; standard output handle
stderr equ 2 ; standard error handle
cr equ 0dh ; ASCII carriage return
lf equ 0ah ; ASCII line feed
DGROUP group _DATA
_DATA segment word public 'DATA'
modesw dd 0 ; far pointer to DPMI mode
; switch entry point
int0dv dd 0 ; address of previous
; GP fault handler
int21v dd 0 ; address of previous
; Int 21H handler
realseg dw 0 ; segment of real mode buffer
realsel dw 0 ; selector for real mode buffer
gpfmsg db cr,lf,lf
db 'TINYDOSX: general protection fault!'
db cr,lf
gpfmsg_len equ $-gpfmsg
abmsg db cr,lf,lf
db 'TINYDOSX: unsupported DOS function!'
db cr,lf
abmsg_len equ $-abmsg
regs label word ; real mode register structure
; for DPMI translation services
regDI label word ; 00H DI or EDI
regEDI dd 0
regSI label word ; 04H SI or ESI
regESI dd 0
regBP label word ; 08H BP or EBP
regEBP dd 0
dd 0 ; 0CH (reserved)
regBX label word ; 10H BX or EBX
regEBX dd 0
regDX label word ; 14H DX or EDX
regEDX dd 0
regCX label word ; 18H CX or ECX
regECX dd 0
regAX label word ; 1CH AX or EAX
regEAX dd 0
cpuFLAGS dw 0 ; 20H cpu status flags
regES dw 0 ; 22H ES
regDS dw 0 ; 24H DS
regFS dw 0 ; 26H FS
regGS dw 0 ; 28H GS
regIP dw 0 ; 2AH IP (CS:IP ignored by
regCS dw 0 ; 2CH CS DPMI function 0300H)
regSP dw 0 ; 2EH SP (SS:SP=0 to have DPMI
regSS dw 0 ; 30H SS host supply a stack)
protDX dw 0 ; save protected mode DX
protSI dw 0 ; save protected mode SI
protES dw 0 ; save protected mode ES
dispatch label word ; Int 21H dispatch table
dw offset _TEXT:fxn00h ; fxn 00H terminate
dw offset _TEXT:fxn01h ; fxn 01H char input+echo
dw offset _TEXT:fxn02h ; fxn 02H char output
dw offset _TEXT:fxn03h ; fxn 03H aux input
dw offset _TEXT:fxn04h ; fxn 04H aux output
dw offset _TEXT:fxn05h ; fxn 05H printer output
dw offset _TEXT:fxn06h ; fxn 06H raw console I/O
dw offset _TEXT:fxn07h ; fxn 07H raw input no echo
dw offset _TEXT:fxn08h ; fxn 08H char input no echo
dw offset _TEXT:abort ; fxn 09H
dw offset _TEXT:abort ; fxn 0AH
dw offset _TEXT:fxn0bh ; fxn 0BH input status
dw offset _TEXT:abort ; fxn 0CH
dw offset _TEXT:fxn0dh ; fxn 0DH disk reset
dw offset _TEXT:fxn0eh ; fxn 0EH select disk
dw offset _TEXT:abort ; fxn 0FH
dw offset _TEXT:abort ; fxn 10H
dw offset _TEXT:abort ; fxn 11H
dw offset _TEXT:abort ; fxn 12H
dw offset _TEXT:abort ; fxn 13H
dw offset _TEXT:abort ; fxn 14H
dw offset _TEXT:abort ; fxn 15H
dw offset _TEXT:abort ; fxn 16H
dw offset _TEXT:abort ; fxn 17H
dw offset _TEXT:abort ; fxn 18H
dw offset _TEXT:fxn19h ; fxn 19H get current drive
dw offset _TEXT:abort ; fxn 1AH
dw offset _TEXT:fxn1bh ; fxn 1BH get cur. drive data
dw offset _TEXT:fxn1ch ; fxn 1CH get drive data
dw offset _TEXT:abort ; fxn 1DH
dw offset _TEXT:abort ; fxn 1EH
dw offset _TEXT:abort ; fxn 1FH
dw offset _TEXT:abort ; fxn 20H
dw offset _TEXT:abort ; fxn 21H
dw offset _TEXT:abort ; fxn 22H
dw offset _TEXT:abort ; fxn 23H
dw offset _TEXT:abort ; fxn 24H
dw offset _TEXT:abort ; fxn 25H
dw offset _TEXT:abort ; fxn 26H
dw offset _TEXT:abort ; fxn 27H
dw offset _TEXT:abort ; fxn 28H
dw offset _TEXT:abort ; fxn 29H
dw offset _TEXT:fxn2ah ; fxn 2AH get date
dw offset _TEXT:fxn2bh ; fxn 2BH set date
dw offset _TEXT:fxn2ch ; fxn 2CH get time
dw offset _TEXT:fxn2dh ; fxn 2DH set time
dw offset _TEXT:fxn2eh ; fxn 2EH set verify flag
dw offset _TEXT:abort ; fxn 2FH
dw offset _TEXT:fxn30h ; fxn 30H get DOS version
dw offset _TEXT:abort ; fxn 31H
dw offset _TEXT:abort ; fxn 32H
dw offset _TEXT:fxn33h ; fxn 33H get/set break flag
dw offset _TEXT:abort ; fxn 34H
dw offset _TEXT:abort ; fxn 35H
dw offset _TEXT:fxn36h ; fxn 36H get drive info
dw offset _TEXT:abort ; fxn 37H
dw offset _TEXT:error ; fxn 38H
dw offset _TEXT:fxn39h ; fxn 39H create directory
dw offset _TEXT:fxn3ah ; fxn 3AH delete directory
dw offset _TEXT:fxn3bh ; fxn 3BH select directory
dw offset _TEXT:fxn3ch ; fxn 3CH create file
dw offset _TEXT:fxn3dh ; fxn 3DH open file
dw offset _TEXT:fxn3eh ; fxn 3EH close file
dw offset _TEXT:fxn3fh ; fxn 3FH read file
dw offset _TEXT:fxn40h ; fxn 40H write file
dw offset _TEXT:fxn41h ; fxn 41H delete file
dw offset _TEXT:fxn42h ; fxn 42H seek
dw offset _TEXT:fxn43h ; fxn 43H get/set attributes
dw offset _TEXT:error ; fxn 44H
dw offset _TEXT:fxn45h ; fxn 45H dup handle
dw offset _TEXT:fxn46h ; fxn 46H redirect handle
dw offset _TEXT:fxn47h ; fxn 47H get cur. directory
dw offset _TEXT:error ; fxn 48H
dw offset _TEXT:error ; fxn 49H
dw offset _TEXT:error ; fxn 4AH
dw offset _TEXT:error ; fxn 4BH
dw offset _TEXT:fxn4ch ; fxn 4CH terminate
dw offset _TEXT:abort ; fxn 4DH
dw offset _TEXT:error ; fxn 4EH
dw offset _TEXT:error ; fxn 4FH
dw offset _TEXT:abort ; fxn 50H
dw offset _TEXT:abort ; fxn 51H
dw offset _TEXT:abort ; fxn 52H
dw offset _TEXT:abort ; fxn 53H
dw offset _TEXT:fxn54h ; fxn 54H get verify flag
dw offset _TEXT:abort ; fxn 55H
dw offset _TEXT:error ; fxn 56H
dw offset _TEXT:fxn57h ; fxn 57H get/set file date
dw offset _TEXT:error ; fxn 58H
dw offset _TEXT:abort ; fxn 59H
dw offset _TEXT:fxn5ah ; fxn 5AH create temp file
dw offset _TEXT:fxn5bh ; fxn 5BH create unique file
dw offset _TEXT:fxn5ch ; fxn 5CH lock/unlock
dw offset _TEXT:abort ; fxn 5DH
dw offset _TEXT:error ; fxn 5EH
dw offset _TEXT:error ; fxn 5FH
dw offset _TEXT:abort ; fxn 60H
dw offset _TEXT:abort ; fxn 61H
dw offset _TEXT:abort ; fxn 62H
dw offset _TEXT:error ; fxn 63H
dw offset _TEXT:abort ; fxn 64H
dw offset _TEXT:error ; fxn 65H
dw offset _TEXT:error ; fxn 66H
dw offset _TEXT:error ; fxn 67H
dw offset _TEXT:fxn68h ; fxn 68H commit file
dw offset _TEXT:abort ; fxn 69H
dw offset _TEXT:abort ; fxn 6AH
dw offset _TEXT:abort ; fxn 6BH
dw offset _TEXT:error ; fxn 6CH
dw offset _TEXT:abort ; fxn 6DH
dw offset _TEXT:abort ; fxn 6EH
dw offset _TEXT:abort ; fxn 6FH
_DATA ends
_TEXT segment byte public 'CODE'
assume cs:_TEXT,ds:DGROUP
;
; Initialization routine for the Tiny DOS Extender. First we test for
; the presence of a DPMI host, get the address of the mode switch entry
; point, and request the switch to protected mode. Then we install
; a handler for GP faults to circumvent the Win 3 brain-damaged dialog
; box, and allocate some memory below 1 MB to use as a buffer for
; communication with DOS. Finally we install our own Int 21H handler
; so we can service DOS calls from the protected mode application.
;
public initdosx
initdosx proc near
mov ax,1687h ; get address of DPMI
int 2fh ; mode switch entry point
or ax,ax ; bail out if no DPMI
jnz init9
mov word ptr modesw,di ; save far pointer to
mov word ptr modesw+2,es ; DPMI entry point
mov bx,si ; allocate DPMI private data
mov ah,48h ; area below 1 MB boundary
int 21h
jc init9 ; jump, allocation failed
mov es,ax ; pass segment of data area
mov ax,0 ; bit 0=0 indicates 16-bit app
call modesw ; switch to protected mode
mov ax,0202h ; get address of previous
mov bl,0dh ; owner of GP fault vector
int 31h
mov word ptr int0dv,dx ; save as far pointer
mov word ptr int0dv+2,cx
mov ax,0203h ; install our GP fault handler
mov bl,0dh
mov cx,cs ; CX:DX = handler address
mov dx,offset _TEXT:gpfisr
int 31h
jc init9 ; jump, couldn't install
mov ax,0100h ; allocate 64 KB buffer in
mov bx,1000h ; conventional memory for
int 31h ; communication with DOS
jc init9 ; jump, allocation failed
mov realseg,ax ; save segment of block
mov realsel,dx ; save selector for block
mov ax,0204h ; get address of previous
mov bl,21h ; owner of Int 21H vector
int 31h
mov word ptr int21v,dx ; save as far pointer
mov word ptr int21v+2,cx
mov ax,0205h ; install our Int 21H handler
mov bl,21h
mov cx,cs ; CX:DX = handler address
mov dx,offset _TEXT:doscall
int 31h
xor ax,ax ; return in protected mode
ret ; AX = 0 to signal success
init9: mov ax,-1 ; return with AX <> 0 to
ret ; signal initialization failure
initdosx endp
;
; Interrupt service routine for GP faults. Entered by a far call
; from DPMI host with CS:IP, flags, CPU error code on stack.
; We force transfer to our error message routine by changing
; return address in the stack frame.
;
gpfisr proc far
push bp ; point CS:IP in stack frame to
mov bp,sp ; GP fault error message routine
mov word ptr [bp+8],offset _TEXT:gpferr
pop bp
ret
gpfisr endp
;
; This routine gains control after the GPFISR returns to the DPMI host.
; It simply displays an error message and terminates cleanly, subverting
; Win 3's "Application has violated system integrity" dialog box.
;
gpferr proc near
mov dx,offset DGROUP:gpfmsg ; display GP fault message
mov cx,gpfmsg_len ; on standard output
mov bx,stdout
mov ah,40h
int 21h
mov ax,4c01h ; and terminate with
int 21h ; nonzero return code
gpferr endp
;
; The DOSCALL routine is the runtime portion of the Tiny DOS Extender.
; It traps Int 21H requests in protected mode and performs any necessary
; mode switching, data movement, and address translation on a
; function-by-function basis. Anything DOSCALL doesn't want to handle,
; it either fails by setting the Carry flag and returning, or
; it aborts the current program. In particular, all FCB-related
; functions are aborted. When a termination function is detected,
; the interrupt handlers are unhooked and the function call is
; passed down to the DPMI host so that all other protected mode
; resources will be deallocated.
;
doscall proc far
push bx ; save register BX
mov bl,ah ; function number * 2
xor bh,bh
cmp bx,6fh ; function no. too big?
ja abort ; yes, bail out
add bx,bx ; no, branch through table
jmp [dispatch+bx] ; to function handler
abort: ; unsupported DOS function
mov dx,offset DGROUP:abmsg ; display error message
mov cx,abmsg_len
mov bx,stdout
mov ah,40h
int 21h
mov ax,4c01h ; and exit to DOS
int 21h
error: ; unsupported DOS function
push bp ; set Carry flag in stack
mov bp,sp ; frame to indicate
or word ptr [bp+6],1 ; function failed
pop bp ; load AX = error code for
mov ax,1 ; "invalid function number"
iret ; return to application
; common handling for entirely
; register-based functions
fxn01h: ; function 01H: char input+echo
fxn02h: ; function 02H: char output
fxn03h: ; function 03H: aux input
fxn04h: ; function 04H: aux output
fxn05h: ; function 05H: printer output
fxn06h: ; function 06H: raw console I/O
fxn07h: ; function 07H: raw input no echo
fxn08h: ; function 08H: char input no echo
fxn0bh: ; function 0BH: input status
fxn0dh: ; function 0DH: disk reset
fxn0eh: ; function 0EH: select disk
fxn19h: ; function 19H: get current drive
fxn1bh: ; function 1BH: get cur. drive data
fxn1ch: ; function 1CH: get drive data
fxn2ah: ; function 2AH: get date
fxn2bh: ; function 2BH: set date
fxn2ch: ; function 2CH: get time
fxn2dh: ; function 2DH: set time
fxn2eh: ; function 2EH: set verify flag
fxn30h: ; function 30H: get DOS version
fxn33h: ; function 33H: get/set break flag
fxn36h: ; function 36H: get drive info
fxn3eh: ; function 3EH: close file
fxn42h: ; function 42H: seek
fxn45h: ; function 45H: dup handle
fxn46h: ; function 46H: redirect handle
fxn54h: ; function 54H: get verify flag
fxn57h: ; function 57H: get/set filedate
fxn5ch: ; function 5CH: lock/unlock
fxn68h: ; function 68H: commit file
pop bx ; restore BX
call saveregs ; unload general registers
call realdos ; transfer to DOS
call loadregs ; load general registers & flags
iret ; return to application
; common handling for functions
; passing ASCIIZ addr in DS:DX
fxn39h: ; function 39H: create directory
fxn3ah: ; function 3AH: delete directory
fxn3bh: ; function 3BH: select directory
fxn3ch: ; function 3CH: create file
fxn3dh: ; function 3DH: open
fxn41h: ; function 41H: delete file
fxn43h: ; function 43H: get/set attributes
fxn5ah: ; function 5AH: create temp file
fxn5bh: ; function 5BH: create unique file
pop bx ; restore BX
call saveregs ; unload general registers
mov es,realsel ; ES:DI = virtual address of
xor di,di ; real mode buffer
mov si,dx ; DS:SI = virtual address of
cld ; protected mode buffer
@@1: lodsb ; copy ASCIIZ string to
stosb ; real mode buffer
or al,al ; reached null yet?
jnz @@1 ; no, copy another character
mov ax,realseg ; set address of real mode buffer
mov regDS,ax ; into register data structure
mov regDX,0
call realdos ; transfer to MS-DOS
call loadregs ; load general registers & flags
mov dx,protDX ; restore protected mode DX, ES
mov es,protES
iret ; return to application
fxn3fh: ; function 3FH: read file
pop bx ; restore BX
call saveregs ; unload general registers
mov ax,realseg ; set address of real mode buffer
mov regDS,ax ; into register data structure
mov regDX,0
call realdos ; transfer to MS-DOS
mov cx,regCX ; CX = actual length of data
push ds ; ES:DI = virtual address of
pop es ; protected mode buffer
mov di,protDX
mov ds,realsel ; DS:SI = virtual address of
xor si,si ; real mode buffer
cld ; copy data from real mode
rep movsb ; buffer to protected mode buffer
push es ; restore DS = our DGROUP
pop ds
call loadregs ; load general registers
mov dx,protDX ; restore protected mode DX, ES
mov es,protES
iret ; return to application
fxn40h: ; function 40H: write file
pop bx ; restore BX
call saveregs ; unload general registers
mov es,realsel ; ES:DI = virtual address of
xor di,di ; real mode buffer
mov si,dx ; DS:SI = virtual address of
cld ; protected mode buffer
rep movsb ; copy data to real mode buffer
mov ax,realseg ; set address of real mode buffer
mov regDS,ax ; into register data structure
mov regDX,0
call realdos ; transfer to MS-DOS
call loadregs ; load general registers & flags
mov dx,protDX ; restore protected mode DX, ES
mov es,protES
iret ; return to application
fxn47h: ; function 47H: get directory
pop bx ; restore BX
call saveregs ; unload general registers
mov ax,realseg ; set address of real mode buffer
mov regDS,ax ; into register data structure
mov regSI,0
call realdos ; transfer to MS-DOS
push ds ; ES:DI = virtual address of
pop es ; protected mode buffer
mov di,protSI
mov ds,realsel ; DS:SI = virtual address of
xor si,si ; real mode buffer
cld
@@2: lodsb ; copy ASCIIZ string from real
stosb ; mode buffer to prot mode buffer
or al,al ; found null character yet?
jnz @@2 ; no, copy another character
push es ; restore DS = our DGROUP
pop ds
call loadregs ; load general registers
mov si,protSI ; restore protected mode SI, ES
mov es,protES
iret ; return to application
fxn00h: ; function 00H: terminate
fxn4ch: pop bx ; function 4CH: terminate
push ax ; save return code
mov ax,0203h ; restore old GP fault handler
mov bl,0dh
mov cx,word ptr int0dv+2
mov dx,word ptr int0dv
int 31h
mov ax,0205h ; restore old Int 21H handler
mov bl,21h
mov cx,word ptr int21v+2
mov dx,word ptr int21v
int 31h
mov ax,0101h ; release real mode buffer
mov dx,realsel
int 31h
pop ax ; chain to DPMI Int 21H handler
int 21h ; for cleanup and termination
chain: ; general fallthrough point
; (useful during debugging)
pop bx ; restore register BX
jmp int21v ; chain to prev Int 21H owner
doscall endp
;
; Save general registers into real mode data structure for a call to
; real mode routine via DPMI translation services. Note that segment
; registers are NOT unloaded into structure because they are not valid
; for real mode anyway.
;
saveregs proc near
mov regAX,ax ; save general registers
mov regBX,bx
mov regCX,cx
mov regDX,dx
mov regSI,si
mov regDI,di
mov regBP,bp
mov protDX,dx ; extra copies for non-
mov protSI,si ; register-based functions
mov protES,es
ret
saveregs endp
;
; Load general registers from real mode data structure. Note that
; segment registers are NOT loaded because their real mode values
; would cause a GP fault in protected mode.
;
loadregs proc near
mov bp,sp ; update CPU flags in
push cpuFLAGS ; stack frame to return
pop [bp+6] ; DOS function status
mov ax,regAX ; load general registers
mov bx,regBX
mov cx,regCX
mov dx,regDX
mov si,regSI
mov di,regDI
mov bp,regBP
ret
loadregs endp
;
; Call the DPMI translation function 0300H to simulate a real mode
; software interrupt 21H, transferring control to MS-DOS, passing
; the values stored into the real mode register structure 'regs'.
;
realdos proc near
push es
mov ax,0300h ; DPMI Function 0300H
mov bl,21h ; software interrupt 21H
mov bh,0 ; flags (bit 0 must be 0)
mov cx,0 ; no. of stack words to copy
push ds ; ES:DI = address of real
pop es ; mode register structure
mov di,offset DGROUP:regs
int 31h ; to DOS via DPMI host
pop es
ret
realdos endp
_TEXT ends
end