home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
GLEN
/
TSRSRC32.ZIP
/
WATCH.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-11-22
|
24KB
|
671 lines
;WATCH.ASM
;resident routine watches programs going resident
;and keeps a list of interrupt vector changes in an internal data structure
;==============================================================================
; to be assembled by TASM
; Copyright (c) 1986,1991 Kim Kokkonen, TurboPower Software.
; May be freely distributed but not sold except by permission.
; telephone: 719-260-6641, Compuserve 76004,2611
;==============================================================================
; version 2.2 3/4/87
; First release, version to be consistent with MAPMEM.PAS
; :
; long intervening history
; :
; version 3.0 9/24/91
; add tracking for TSRs that unload themselves
; add support for TSRs loaded high
; WATCH may be loaded high
; version 3.1 11/4/91
; rewrite again to solve problems with SWAPMM, FSP, DATAPATH, DATAMON
; version 3.2 11/22/91
; change method of accessing high memory
; deal with DOS 5 MODE int trapping (int seg < psp seg)
;==============================================================================
;
;uncomment following line to generate more publics in MAP file
; debug = 1
cseg segment public para
assume cs:cseg, ds:nothing, es:nothing, ss:nothing
locals @@
org 080H
cmdline label byte ;pointer to command line
org 100H
pentry: jmp init
;always put the following in WATCH.MAP to update MEMU.PAS
public nextchange,emesg,changevectors,origvectors
;***********************************************************************
;data structures part of COM file
even
nextchange dw 0 ;next position to write in changes area
firstmcb dw ? ;first MCB segment
firsthimcb dw 0 ;first MCB segment in high memory
;temporary stack used by interrupt handler
newsp dw ? ;initial stack pointer
newss dw ? ;segment of our temporary stack (=cseg)
tmpret dw ? ;used while switching stacks
;information saved about the calling program
oldsp dw ? ;stack pointer
oldss dw ? ;stack segment
;previous interrupt handlers
dos_int label dword
old21 dw 2 dup (?) ;old int21 vector
tsr_int label dword
old27 dw 2 dup (?) ;old int27 vector
;id code for a PSP data block
pspid equ 0FFFFH ;id used to indicate a PSP block
;structure of a changevectors data block
pspblock struc
id dw ? ;id word, always pspid
psp dw ? ;psp segment
len dw ? ;length of psp
unu1 dw ? ;unused
pspblock ends
vecblock struc
vec dw ? ;vector number 0..255
veco dw ? ;vector offset
vecs dw ? ;vector segment
unu2 dw ? ;unused
vecblock ends
;***********************************************************************
;resident data structures not part of COM file
changevectors = offset emesg ;data area overwrites emesg & beyond
vrecsize = 8 ;number of bytes per vector change record
maxchanges = 128 ;maximum number of vector changes
vsize = maxchanges*vrecsize ;size of vector change area in bytes
;vector table buffers
origvectors = offset changevectors+vsize ;location of original vector table
veclen = 1024 ;size of vector table in bytes
newstackpos = origvectors+veclen ;location of newstack
ssize = 128 ;number of bytes in temporary stack
newloc = newstackpos+ssize ;location for relocated installation code
;***********************************************************************
;int21 handler
; traps functions 31, 49, 4C, and 7761
int21h proc far
ifdef debug
public int21h
endif
assume ds:nothing
pushf ;save flags
sti ;allow interrupts
cmp ah,31H ;terminate and stay resident call?
jne @@1
call addcurrpsp ;dx = paras to keep
jmp short @@4
@@1: cmp ah,49H ;deallocate block call?
jne @@2
call remblock ;remove specified block if a psp
jmp short @@4
@@2: cmp ah,4CH ;normal program halt?
jne @@3
call checkblocks
jmp short @@4
@@3: cmp ax,7761H ;"wa"tch ID call?
jne @@4
call checkblocks ;assure change list up to date
push bp
mov bp,sp ;set up stack frame
and word ptr [bp+8],0FFFEH ;clear carry flag
pop bp
xchg ah,al ;flip ah and al as a signature
mov bx,cs ;return WATCH psp in bx
popf
iret ;return to caller
@@4: popf
jmp dos_int ;let DOS take over
int21h endp
;***********************************************************************
;int27 handler
; watches for programs going resident
int27h proc far
ifdef debug
public int27h
endif
assume ds:nothing
pushf
sti
push dx
add dx,15 ;pass size of block in paras to addcurrpsp
shr dx,1
shr dx,1
shr dx,1
shr dx,1
call addcurrpsp ;get current psp and add block to list
pop dx
popf
jmp tsr_int
int27h endp
;***********************************************************************
;get current PSP in bx and add new block
;entry: dx = paragraphs to keep
addcurrpsp proc near
ifdef debug
public addcurrpsp
endif
assume ds:nothing
call setup ;switch stacks and save registers
assume ds:cseg
mov ah,51H ;get current PSP in bx
pushf
call dos_int
call addblock ;add block at bx, length dx to changes
call shutdown ;restore registers and switch stacks
assume ds:nothing
ret
addcurrpsp endp
;***********************************************************************
;remove PSP block, if any, specified by es
remblock proc near
ifdef debug
public remblock
endif
assume ds:nothing
call setup ;switch stacks and save registers
assume ds:cseg
mov bx,es ;save segment being deallocated in bx
call matchpsp ;return offset in changevectors of segment
or si,si ;any matching block?
jz @@1
call rempsp ;remove psp
@@1: call shutdown ;restore registers and switch stacks
assume ds:nothing
ret
remblock endp
;***********************************************************************
;scan chain of mcbs starting at segment ax
;remove halting psp from change list if needed
checkchain proc near
ifdef debug
public checkchain
endif
@@1: mov es,ax
mov bx,es:[0001h] ;bx = psp of block
mov dx,es:[0003h] ;dx = len of block
inc ax
cmp ax,bx ;does psp = mcb+1?
jne @@2 ;jump if not
cmp ax,cx ;does psp = current program?
je @@2 ;jump if so
push dx
call matchpsp ;find matching psp in changevectors
pop dx
or si,si ;is there a matching psp?
jnz @@2 ;jump if so
push ax
push cx
push dx
call addblock ;add this psp
pop dx
pop cx
pop ax
@@2: cmp byte ptr es:[0000h],'Z' ;end of chain
je @@3
add ax,dx
jmp @@1
@@3: ret
checkchain endp
;***********************************************************************
;check for new memory blocks and add if needed
;remove halting psp from change list if needed
checkblocks proc near
ifdef debug
public checkblocks
endif
assume ds:nothing
call setup ;switch stacks and save registers
assume ds:cseg
mov ah,51H ;get current psp in bx
pushf
call dos_int
call matchpsp ;is current program in change list?
or si,si
jz @@0 ;jump if not
call rempsp ;remove it if not
@@0: mov cx,bx ;cx = psp of halting program
mov ax,firstmcb ;start with first mcb
call checkchain ;check this chain
mov ax,firsthimcb ;scan high memory
or ax,ax
jz @@1
call checkchain
@@1: call shutdown ;restore registers and switch stacks
assume ds:nothing
ret
checkblocks endp
;***********************************************************************
;setup routine for interrupt hook routines
; switches stacks, saves registers, sets ds=cs
setup proc near
ifdef debug
public setup
endif
assume ds:nothing
pop cs:tmpret ;save return address as we switch stacks
mov oldss,ss ;save current stack
mov oldsp,sp
cli ;switch to our stack
mov ss,newss
mov sp,newsp
sti
push ax ;store registers
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
push cs ;set ds=cs
pop ds
assume ds:cseg
push cs:tmpret ;return
ret
setup endp
;***********************************************************************
;shutdown routine for interrupt hook routines
; restores registers, switches stacks
shutdown proc near
ifdef debug
public shutdown
endif
pop cs:tmpret
pop es ;restore registers
pop ds
assume ds:nothing
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
cli ;restore stack
mov ss,cs:oldss
mov sp,cs:oldsp
sti
push cs:tmpret ;return
ret
shutdown endp
;***********************************************************************
;add specified block to changes
; entry: bx = psp of block, dx = length of block in paras
addblock proc near
ifdef debug
public addblock
endif
assume ds:cseg
call addhdr ;add a psp header block
call addvecs ;add blocks for each hooked vector
ret
addblock endp
;***********************************************************************
;add header for a psp block
; entry: bx = psp of block, dx = length of block in paras
; exit: alters di
addhdr proc near
ifdef debug
public addhdr
endif
assume ds:nothing
mov di,nextchange
cmp di,vsize-vrecsize ;assure room for next record
ja @@1
mov word ptr cs:changevectors[di].id,pspid
mov cs:changevectors[di].psp,bx
mov cs:changevectors[di].len,dx
add di,vrecsize
mov nextchange,di
@@1: ret
addhdr endp
;***********************************************************************
;add vector blocks for each hooked vector
; entry: bx = psp of block, dx = length of block in paras
; exit: alters ax,cx,dx,si,di,bp
addvecs proc near
ifdef debug
public addvecs
endif
assume ds:cseg
push ds
add dx,bx ;now dx points to end of block
mov di,nextchange ;cs:changevectors[di] -> output area
xor si,si
mov ds,si ;ds:si -> vectors
assume ds:nothing
xor cx,cx ;cx = vector counter
cld ;forward
@@1: lodsw ;ax = vector offset
mov bp,ax ;save vector offset
lodsw ;ax = vector segment
cmp ax,dx ;is vector above high limit?
jae @@3
push cx
mov cx,ax
cmp bp,800h ;don't add unless a small offset
ja @@1a ;(this is a trap for DOS 5 MODE)
push bp
shr bp,1
shr bp,1
shr bp,1
shr bp,1
add cx,bp ;ax = equivalent segment of interrupt
pop bp
@@1a: cmp cx,bx ;is vector above low limit?
jb @@2
pop cx
cmp di,vsize-vrecsize ;room for another entry?
ja @@3
mov cs:changevectors[di].vec,cx ;save entry for this vector
mov cs:changevectors[di].veco,bp
mov cs:changevectors[di].vecs,ax
add di,vrecsize
jmp short @@3
@@2: pop cx
@@3: inc cx ;next vector
cmp cx,0FFh
jbe @@1
mov nextchange,di
pop ds
assume ds:cseg
ret
addvecs endp
;***********************************************************************
;find changeblock matching psp
; entry: bx = psp to match
; exit: si = matching block, or 0 if none
; destroys dx
matchpsp proc near
ifdef debug
public matchpsp
endif
assume ds:cseg
mov si,offset changevectors
mov dx,si
add dx,nextchange ;dx = next unused spot in changevectors
@@1: cmp si,dx ;end of table
jae @@3
cmp word ptr [si].id,pspid ;psp indicator?
jnz @@2 ;jump if not
cmp [si].psp,bx ;matching psp?
jnz @@2 ;jump if not
ret ;else return with match
@@2: add si,vrecsize
jmp @@1
@@3: xor si,si ;no match if here
ret
matchpsp endp
;***********************************************************************
;remove all blocks associated with psp at offset si
; exit: alters cx,dx,si,di,es
rempsp proc near
ifdef debug
public rempsp
endif
assume ds:cseg
mov di,si ;save destination
add si,vrecsize ;move to next record
mov dx,offset changevectors
add dx,nextchange ;dx = address of next unused
@@1: cmp si,dx ;end of table?
jae @@2 ;jump if so
cmp word ptr [si].id,pspid ;next psp indicator?
je @@2 ;jump if so
add si,vrecsize ;next block
jmp @@1 ;and loop
@@2: mov cx,dx
sub cx,si
shr cx,1 ;cx = words to move
push cs
pop es ;es = ds = cs
cld
rep movsw ;copy down remaining blocks
sub si,di
sub nextchange,si ;update nextchange
ret
rempsp endp
;***********************************************************************
;resident portion above, temporary portion below
;***********************************************************************
align 16
emesg db 'Cannot install WATCH more than once....',13,10,36
mesg db 'WATCH 3.2, Copyright 1991 TurboPower Software',13,10
db 'Installed successfully',13,10,36
pname db 'TSR WATCHER'
plen equ $-pname ;length of string
xmsadr label dword ;XMS control address
xmsxxx dw 2 dup (0)
;***********************************************************************
;add dummy changeblocks for all psps already resident in chain starting at ax
addchain proc near
ifdef debug
public addchain
endif
assume ds:cseg
@@1: mov es,ax
mov bx,es:[0001h] ;bx = psp of block
mov dx,es:[0003h] ;dx = len of block
inc ax
cmp ax,bx ;does psp = mcb+1?
jne @@2 ;jump if not
cmp ax,newss ;does psp = WATCH itself?
je @@2 ;jump if so
call addhdr ;add a header for this block
@@2: cmp byte ptr es:[0000h],'Z' ;end of chain
je @@3
add ax,dx
jmp @@1
@@3: ret
addchain endp
;***********************************************************************
;return segment of first high memory mcb in ax
findhimemstart proc near
ifdef debug
public findhimemstart
endif
mov ax,3000h ;get DOS version
int 21H
cmp al,3
jb @@7 ;no XMS driver possible
mov ax,4300h
int 2Fh ;multiplex call for XMS
cmp al,80h ;proper signature?
jne @@7 ;no XMS driver
mov ax,4310h
int 2Fh
mov xmsxxx,bx ;save XMS control address
mov xmsxxx[2],es
mov ah,10h
mov dx,0FFFFh
call xmsadr ;ask to allocate FFFF paras of UMB
cmp bl,0B0h ;will fail with B0 if UMBs avail
je @@0
cmp bl,0B1h ;will fail with B1 if UMBs all allocated
jne @@7 ;no UMBs exist
@@0: int 12H
mov cl,6
shl ax,cl ;get segment of top of memory
@@1: mov es,ax
cmp byte ptr es:[0000h],'M' ;potential mcb?
jnz @@6 ;not an mcb, try next segment
@@2: mov cx,ax ;save potential start mcb in cx
@@3: inc ax
add ax,es:[0003h] ;ax = start of next mcb
jc @@5 ;can't be an mcb if we wrapped
mov es,ax ;address of next mcb
mov dl,es:[0000h]
cmp dl,'M'
jz @@3 ;good start mcb
cmp dl,'Z'
jz @@9 ;good end mcb
@@5: mov ax,cx ;restore last start segment
@@6: cmp ax,0FFFFh ;top of memory?
je @@7
inc ax ;try next segment
jmp @@1
@@7: xor cx,cx ;no matching UMB
@@9: mov ax,cx ;return segment in ax
ret
findhimemstart endp
;***********************************************************************
;add dummy changeblocks for all psps already resident
adddummypsp proc near
ifdef debug
public adddummypsp
endif
assume ds:cseg
mov ah,52H
int 21H ;get DOS list of lists
mov ax,es:[bx-2] ;get first MCB segment
mov firstmcb,ax ;save it for use later too
call addchain
call findhimemstart ;find first high memory mcb
mov firsthimcb,ax ;save it for use later too
or ax,ax
jz @@1
call addchain ;add blocks in high memory too
@@1: ret
adddummypsp endp
;***********************************************************************
init proc near
ifdef debug
public init
endif
assume ds:cseg
;use int 21h test to check for previous installation
mov ax,7761H ;special id function
int 21H
jc @@1 ;not installed if function fails
cmp ax,6177H
jnz @@1 ;not installed if id code not returned
;error exit
mov dx,offset emesg ;error message
mov ah,09H
int 21H ;DOS print string
mov ax,4C01H ;exit with error
int 21H
;not already installed
@@1: mov dx,offset mesg ;success message
mov ah,09H
int 21H ;DOS print string
;initialize location of WATCH stack
mov newsp,newstackpos+ssize
mov newss,cs ;stack seg is code seg
;put an id label at offset 80H to allow other programs to recognize WATCH
mov cx,plen ;length of name string
mov si,offset pname ;offset of name string
mov di,offset cmdline ;offset of DOS command line
cld ;transfer in forward direction
mov al,cl
stosb ;store length byte first
rep movsb ;transfer characters
;add psp records for all blocks already resident
call adddummypsp
;relocate ourselves out of the way of the resident tables
push cs
pop es
mov di,newloc+10H
push di ;will act as a return address
mov si,offset @@2
mov cx,@@3-@@2
rep movsb ;move code
ret ;"return" to the relocated code
;store image of original vector table (overwrites messages and non-res code)
@@2: mov di,origvectors
push ds
xor si,si ;offset 0
mov ds,si ;source address segment 0
mov cx,200H ;512 words to store
rep movsw ;copy vectors to our table
pop ds
;store current int 21 and 27 vectors
mov ax,3527H
int 21H
mov old27,bx
mov old27[2],es
mov ax,3521H
int 21H
mov old21,bx
mov old21[2],es
;install new vectors
mov ax,2527H
mov dx,offset int27h
int 21H
mov ax,2521H
mov dx,offset int21h
int 21H
;terminate and stay resident
mov dx,newloc
add dx,15
mov cl,4
shr dx,cl
mov ax,3100H ;return success code
int 21H ;note WATCH will track itself
@@3:
init endp
cseg ends
end pentry