Category : Utilities for DOS and Windows Machines
Archive   : TSRWRK31.ZIP
Filename : WATCH.ASM

Output of file : WATCH.ASM contained in archive : TSRWRK31.ZIP

;WATCH.ASM Version 3.1 30-May-1989 03:10
;resident routine watches programs going resident
;and keeps a list of changes to interrupt vectors
;in an internal data structure
; written for MASM (version 4 or later) or TASM
; by Kim Kokkonen, TurboPower Software
; telephone: 408-438-8606, Compuserve 72457,2131
; VERSION 2.2 3/4/87
; First release, version to be consistent with MAPMEM.PAS
; VERSION 2.3 5/1/87
; Sets up a separate stack for the interrupt handlers
; to solve problem first noticed with EMMCACHE and WATCH
; Changes approach - store all vector information in RAM buffers
; No disk access at all by WATCH
; Better check for multiple installation
; Changed to use MASM
; VERSION 2.4 5/17/87
; for consistency with RELEASE
; VERSION 2.5 5/28/87
; save flags in int21 handler
; VERSION 3.1 5/30/89 for use with UnMark and ReMark 3.1
; by Tom Gilbert's Heart & Mind includes TurboPower 2.8
; NO [F]Mark INT vectors
; Change method to avoid reinstallation
; Nul Vchg area => vpos to simplify debugging

Cseg segment public para
assume cs:Cseg, ds:nothing, es:nothing, ss:nothing

org 080H
cmdline label byte ;pointer to command line

org 100H
ComEntry: jmp init

;resident data section follows

;put the following in the MAP file
public bmesg,origv,prevv,vpos,vchg
; 0E20h, 620h,0A20h,104h,220h

;resident data structures not part of COM file
vchg equ 220H ;location of data area (>= offset bmesg)
vrecsize equ 8 ;bytes per vector change record
vsize equ 80H*vrecsize ;size of vector change area in bytes
;space for 128 changes of vector here
;vector table buffers
origv equ vchg+vsize ;location of original vector table
veclen equ 400H ;size of vector table in bytes
prevv equ origv+veclen ;location of current vector table
newstackpos equ prevv+veclen ;location of newstack
ssize equ 0080H ;number of bytes in temporary stack

newloc equ newstackpos+ssize ;where installation code relocated
vpos dw 0 ;next position to write in data area

;temporary stack used by interrupt handler
newss dw 0 ;segment of temporary stack
newsp dw 0 ;initial stack pointer

;information saved about the calling program
oldss dw ? ;stack segment
oldsp dw ? ;stack pointer
curpsp dw ? ;program segment

;id code for a PSP data block
pspid equ 0FFFFH ;id used to indicate a PSP block

;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

;interrupt handler for int21
newint21 proc near
assume ds:nothing
pushf ;save flags
cmp ah,31H
jne ex21
call checkvec ;call routine to check vector table
ex21: popf
jmp dos_int ;transfer control to old int21 vector
newint21 endp

;interrupt handler for int27
newint27 proc near
assume ds:nothing
call checkvec
ex27: jmp tsr_int ;transfer control to old int27 vector
newint27 endp


;procedure checkvec
; compares vectors to previous installation
; writes vector change information
; stores a new vector buffer

checkvec proc near
assume ds:nothing

;save current stack
mov oldss,ss
mov oldsp,sp

;switch to our stack
mov ss,newss
mov sp,newsp
;store registers
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
;get DS set up as CS
mov ax,cs
mov ds,ax
assume ds:Cseg
mov ah,51H ;get current PSP
pushf ;by simulated INT
call dos_int ;bx returns PSP
call vechdr ;store PSP segment of program going resident
call cmpvec ;scan vector table for changes from buffer
mov di,prevv ;save the new version of the vector table
call savevec
;restore registers
pop es
pop ds
assume ds:nothing
pop di
pop si
pop dx
pop cx
pop bx
pop ax
;restore stack
mov ss,oldss
mov sp,oldsp
checkvec endp

;procedure vechdr
; writes a header to the vector data area for this new TSR
; on entry:
; bx has PSP of the new TSR
vechdr proc near
assume ds:Cseg
cmp vpos,vsize-vrecsize ;assure room for next record
ja vecex ;ignore if no room
push di
mov di,vpos ;index into vchg array
mov word ptr [di+vchg],pspid ;store id word
mov word ptr [di+vchg+2],bx ;store PSP value two words in
;record left unitialized
add vpos,vrecsize ;move to next data element
pop di

vecex: ret
vechdr endp

;procedure wrchg
; writes information about changed vectors to the data area
; on entry
; ax has changed vector number
; ds points to segment 0
; on exit:
; flags changed
wrchg proc near
assume ds:nothing, es:nothing
cmp vpos,vsize-vrecsize ;assure room for next record
ja wrcex

push ax
push si
push di

mov di,vpos ;index into vchg array
mov cs:[di+vchg],ax ;store interrupt vector number

mov si,ax
shl si,1
shl si,1 ;get address of vector
mov ax,[si] ;get offset of vector
mov cs:[di+vchg+2],ax ;store vector offset
mov ax,[si+2] ;get segment
mov cs:[di+vchg+4],ax ;store segment
;one word in record left unused
add vpos,vrecsize ;move to next data element

pop di
pop si
pop ax

wrcex: ret
wrchg endp

;procedure cmpvec
; compares vectors in buffer to those in use
; writes numbers of those different to data area
; on entry:
; bx has program's PSP
; on exit:
; ax,si,di destroyed
; flags changed
cmpvec proc near
push ds
push es
assume es:nothing
mov es,bx ;If NO " T"
cmp word ptr es:[65h],'T '
jne dovecs ;then NOT [F]Mark
cmp word ptr es:[67h],'RS'
je cvexit ;else " TSR" is [F]Mark

dovecs: assume ds:nothing
xor si,si ;source offset 0
mov ds,si ;source address segment 0
mov ax,cs
mov es,ax
xor ax,ax ;vector counter
mov di,prevv ;destination offset
cld ;upward direction

nexvec: cmpsw ;compare offsets
je cmpseg ;compare segments if offsets equal
call wrchg ;write changed vector
cmpsw ;compare next word, ignore result
jmp short vecinc

cmpseg: cmpsw ;compare segments
je vecinc
call wrchg ;write changed vector

vecinc: inc ax ;next vector number
cmp ax,00FFH
jbe nexvec ;continue until 256 vectors checked

cvexit: pop es
pop ds
cmpvec endp

;procedure savevec
; saves image of interrupt vectors
; on entry:
; di has destination offset
; on exit:
; ax,cx,si,di destroyed
; flags changed
savevec proc near
assume ds:nothing, es:nothing
push ds
push es
xor si,si ;offset 0
mov ds,si ;source address segment 0
mov ax,cs
mov es,ax ;destination always in this code segment
mov cx,200H ;512 integers to store
cld ;copy up
rep movsw ;copy vectors to our table
pop es
pop ds
savevec endp ;of proc savevec

;resident portion above
;temporary portion below

;temporary strings
bmesg db 13,10,'Cannot install WATCH more than once....',13,10,36
mesg db 13,10,'WATCH 3.1 successfully installed',13,10,36
pname db 'TSR WATCHER'
plen equ $-pname ;length of string

;install new handlers for DOS go-resident services
init proc near
assume ds:Cseg
;search for a previous installation after DOS Master Environment
mov ah,52h ;Use Undocumented Interrupt
int 21h ; to locate DOS CONFIG.SYS
mov ax,es:[bx-2] ;Use its
mov es,ax ;MCB and
inc ax ;Block to
add ax,es:[3] ; add in
mov es,ax ;lengths to
inc ax ;location of
add ax,es:[3] ;environment
mov es,ax ;MCB to begin
mov bx,cs ;comparisons
watchs: inc ax ;If next segment
mov es,ax ;to be compared
cmp ax,bx ;is NOT before here
jnc success ;then NO other Watch
mov si,offset pname ;else compare pname
mov di,81h ;with command line
mov cx,plen ;"TSR WATCHER"
rep cmpsb ;If NO match
jne watchs ;then loop
;error exit
mov dx,offset bmesg ;else error message
mov ah,09H ;NOT more than once
int 21H ;DOS print string
mov ax,4C01H ;exit with error
int 21H
success: ;print a success message
mov dx,offset mesg ;start of message to write
mov ah,09H
int 21H ;DOS print string

;relocate ourselves out of the way of the vector tables
mov ax,cs
mov es,ax
mov di,newloc+10H
push di ;will act as a return address
mov si,offset newstk
mov cx,lastcode-newstk
rep movsb ;move code
ret ;"return" to the relocated code

;initialize location of WATCH stack
newstk: mov newsp,newstackpos+ssize
mov newss,cs ;stack seg is code seg
push es

;get int 21H vector
mov ax,3521H ;GetVector DOS function call
int 21H
mov old21,bx ;store first word of old21
mov old21[2],es ;store second word

;get int 27H vector
mov ax,3527H ;GetVector DOS function call
int 21H
mov old27,bx ;store first word of old27 (offset)
mov old27[2],es ;store second word (segment)
pop es
push es
mov es,es:[2Ch]
mov ah,49h ; Release Environment and
int 21h ; put an id label at
mov ax,cs ; offset 80H so other programs
mov es,ax ; can 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
xor ax,ax ;nul-out
mov di,vchg ;vector change
mov cx,200h ;table area
rep stosw

;store image of original vector table in origv following vchg table
mov ax,offset savevec
call ax ;absolute call works as code is moved

;store it again in the current vector table prevv which follows origv
mov ax,offset savevec
call ax ;absolute call works as code is moved

;install the new vectors
mov ax,2521H
mov dx,offset newint21
int 21H
mov ax,2527H
mov dx,offset newint27
int 21H

;terminate and stay resident
mov dx,(newloc+15) shr 4
mov ax,3100H ;return success code
int 21H

init endp

Cseg ends
end ComEntry