home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / SYSUTL / TSRSRC31.ZIP / WATCH.ASM < prev    next >
Encoding:
Assembly Source File  |  1991-11-04  |  22.6 KB  |  665 lines

  1. ;WATCH.ASM
  2. ;resident routine watches programs going resident
  3. ;and keeps a list of interrupt vector changes in an internal data structure
  4. ;==============================================================================
  5. ; to be assembled by TASM
  6. ; Copyright (c) 1986,1991 Kim Kokkonen, TurboPower Software.
  7. ; May be freely distributed but not sold except by permission.
  8. ; telephone: 719-260-6641, Compuserve 76004,2611
  9. ;==============================================================================
  10. ; version 2.2  3/4/87
  11. ;   First release, version to be consistent with MAPMEM.PAS
  12. ; :
  13. ; long intervening history
  14. ; :
  15. ; version 3.0  9/24/91
  16. ;   add tracking for TSRs that unload themselves
  17. ;   add support for TSRs loaded high
  18. ;   WATCH may be loaded high
  19. ; version 3.1  11/4/91
  20. ;   rewrite again to solve problems with SWAPMM, FSP, DATAPATH, DATAMON
  21. ;==============================================================================
  22. ;
  23. ;uncomment following line to generate more publics in MAP file
  24. ;define debug
  25.  
  26. cseg    segment public para
  27.         assume  cs:cseg, ds:nothing, es:nothing, ss:nothing
  28.         locals  @@
  29.  
  30.         org     080H
  31. cmdline label   byte                    ;pointer to command line
  32.  
  33.         org     100H
  34. pentry: jmp     init
  35.  
  36. ;always put the following in WATCH.MAP to update MEMU.PAS
  37. public nextchange,emesg,changevectors,origvectors
  38.  
  39. ;***********************************************************************
  40. ;data structures part of COM file
  41.                 even
  42. nextchange      dw      0               ;next position to write in changes area
  43.  
  44. dosver          dw      ?               ;DOS version number
  45. umbstat         dw      ?               ;UMB link status
  46. firstmcb        dw      ?               ;first MCB segment
  47.  
  48. ;temporary stack used by interrupt handler
  49. newsp           dw      ?               ;initial stack pointer
  50. newss           dw      ?               ;segment of our temporary stack (=cseg)
  51. tmpret          dw      ?               ;used while switching stacks
  52.  
  53. ;information saved about the calling program
  54. oldsp           dw      ?               ;stack pointer
  55. oldss           dw      ?               ;stack segment
  56.  
  57. ;for saving last 16 bytes, wiped out when opening high memory
  58. topseg          dw      ?               ;segment at top of memory to save
  59. mcbbuf          dw 8 dup (?)            ;buffer to save it in
  60.  
  61. ;previous interrupt handlers
  62. dos_int         label dword
  63. old21           dw 2 dup (?)            ;old int21 vector
  64. tsr_int         label dword
  65. old27           dw 2 dup (?)            ;old int27 vector
  66.  
  67. ;id code for a PSP data block
  68. pspid           equ     0FFFFH          ;id used to indicate a PSP block
  69.  
  70. ;structure of a changevectors data block
  71. pspblock        struc
  72.                 id      dw      ?       ;id word, always pspid
  73.                 psp     dw      ?       ;psp segment
  74.                 len     dw      ?       ;length of psp
  75.                 unu1    dw      ?       ;unused
  76. pspblock        ends
  77. vecblock        struc
  78.                 vec     dw      ?       ;vector number 0..255
  79.                 veco    dw      ?       ;vector offset
  80.                 vecs    dw      ?       ;vector segment
  81.                 unu2    dw      ?       ;unused
  82. vecblock        ends
  83.  
  84. ;***********************************************************************
  85. ;resident data structures not part of COM file
  86. changevectors   =       offset emesg            ;data area overwrites emesg & beyond
  87. vrecsize        =       8                       ;number of bytes per vector change record
  88. maxchanges      =       128                     ;maximum number of vector changes
  89. vsize           =       maxchanges*vrecsize     ;size of vector change area in bytes
  90.  
  91. ;vector table buffers
  92. origvectors     =       offset changevectors+vsize ;location of original vector table
  93. veclen          =       1024                    ;size of vector table in bytes
  94. newstackpos     =       origvectors+veclen      ;location of newstack
  95. ssize           =       128                     ;number of bytes in temporary stack
  96. newloc          =       newstackpos+ssize       ;location for relocated installation code
  97.  
  98. ;***********************************************************************
  99. ;int21 handler
  100. ;  traps functions 31, 49, 4C, and 7761
  101. int21h  proc far
  102. ifdef   debug
  103.         public  int21h
  104. endif
  105.         assume ds:nothing
  106.         pushf                           ;save flags
  107.         sti                             ;allow interrupts
  108.  
  109.         cmp     ah,31H                  ;terminate and stay resident call?
  110.         jne     @@1
  111.         call    addcurrpsp              ;dx = paras to keep
  112.         jmp     short @@4
  113.  
  114. @@1:    cmp     ah,49H                  ;deallocate block call?
  115.         jne     @@2
  116.         call    remblock                ;remove specified block if a psp
  117.         jmp     short @@4
  118.  
  119. @@2:    cmp     ah,4CH                  ;normal program halt?
  120.         jne     @@3
  121.         call    checkblocks
  122.         jmp     short @@4
  123.  
  124. @@3:    cmp     ax,7761H                ;"wa"tch ID call?
  125.         jne     @@4
  126.         call    checkblocks             ;assure change list up to date
  127.         push    bp
  128.         mov     bp,sp                   ;set up stack frame
  129.         and     word ptr [bp+8],0FFFEH  ;clear carry flag
  130.         pop     bp
  131.         xchg    ah,al                   ;flip ah and al as a signature
  132.         mov     bx,cs                   ;return WATCH psp in bx
  133.         popf
  134.         iret                            ;return to caller
  135.  
  136. @@4:    popf
  137.         jmp     dos_int                 ;let DOS take over
  138. int21h  endp
  139.  
  140. ;***********************************************************************
  141. ;int27 handler
  142. ;  watches for programs going resident
  143. int27h  proc far
  144. ifdef   debug
  145.         public int27h
  146. endif
  147.         assume ds:nothing
  148.         pushf
  149.         sti
  150.         push   dx
  151.         add    dx,15            ;pass size of block in paras to addcurrpsp
  152.         shr    dx,1
  153.         shr    dx,1
  154.         shr    dx,1
  155.         shr    dx,1
  156.         call   addcurrpsp       ;get current psp and add block to list
  157.         pop    dx
  158.         popf
  159.         jmp     tsr_int
  160. int27h  endp
  161.  
  162. ;***********************************************************************
  163. ;get current PSP in bx and add new block
  164. ;entry: dx = paragraphs to keep
  165. addcurrpsp proc near
  166. ifdef   debug
  167.         public  addcurrpsp
  168. endif
  169.         assume  ds:nothing
  170.         call    setup           ;switch stacks and save registers
  171.         assume  ds:cseg
  172.         mov     ah,51H          ;get current PSP in bx
  173.         pushf
  174.         call    dos_int
  175.         call    addblock        ;add block at bx, length dx to changes
  176.         call    shutdown        ;restore registers and switch stacks
  177.         assume  ds:nothing
  178.         ret
  179. addcurrpsp endp
  180.  
  181. ;***********************************************************************
  182. ;remove PSP block, if any, specified by es
  183. remblock proc near
  184. ifdef   debug
  185.         public  remblock
  186. endif
  187.         assume  ds:nothing
  188.         call    setup           ;switch stacks and save registers
  189.         assume  ds:cseg
  190.         mov     bx,es           ;save segment being deallocated in bx
  191.         call    matchpsp        ;return offset in changevectors of segment
  192.         or      si,si           ;any matching block?
  193.         jz      @@1
  194.         call    rempsp          ;remove psp
  195. @@1:    call    shutdown        ;restore registers and switch stacks
  196.         assume  ds:nothing
  197.         ret
  198. remblock endp
  199.  
  200. ;***********************************************************************
  201. ;check for new memory blocks and add if needed
  202. ;remove halting psp from change list if needed
  203. checkblocks proc near
  204. ifdef   debug
  205.         public  checkblocks
  206. endif
  207.         assume  ds:nothing
  208.         call    setup                   ;switch stacks and save registers
  209.         assume  ds:cseg
  210.  
  211.         mov     ah,51H                  ;get current psp in bx
  212.         pushf
  213.         call    dos_int
  214.  
  215.         call    matchpsp                ;is current program in change list?
  216.         or      si,si
  217.         jz      @@0                     ;jump if not
  218.         call    rempsp                  ;remove it if not
  219.  
  220. @@0:    mov     cx,bx                   ;cx = psp of halting program
  221.         call    openhigh                ;open high memory if available
  222.         mov     ax,firstmcb             ;start with first mcb
  223.  
  224. @@1:    mov     es,ax
  225.         mov     bx,es:[0001h]           ;bx = psp of block
  226.         mov     dx,es:[0003h]           ;dx = len of block
  227.         inc     ax
  228.         cmp     ax,bx                   ;does psp = mcb+1?
  229.         jne     @@2                     ;jump if not
  230.         cmp     ax,cx                   ;does psp = current program?
  231.         je      @@2                     ;jump if so
  232.         push    dx
  233.         call    matchpsp                ;find matching psp in changevectors
  234.         pop     dx
  235.         or      si,si                   ;is there a matching psp?
  236.         jnz     @@2                     ;jump if so
  237.         push    ax
  238.         push    cx
  239.         push    dx
  240.         call    addblock                ;add this psp
  241.         pop     dx
  242.         pop     cx
  243.         pop     ax
  244. @@2:    cmp     byte ptr es:[0000h],'Z' ;end of chain
  245.         je      @@3
  246.         add     ax,dx
  247.         jmp     @@1
  248.  
  249. @@3:    call    resthigh                ;restore high memory
  250.         call    shutdown                ;restore registers and switch stacks
  251.         assume  ds:nothing
  252.         ret
  253. checkblocks endp
  254.  
  255. ;***********************************************************************
  256. ;setup routine for interrupt hook routines
  257. ; switches stacks, saves registers, sets ds=cs
  258. setup   proc    near
  259. ifdef   debug
  260.         public  setup
  261. endif
  262.         assume  ds:nothing
  263.         pop     cs:tmpret       ;save return address as we switch stacks
  264.         mov     oldss,ss        ;save current stack
  265.         mov     oldsp,sp
  266.         cli                     ;switch to our stack
  267.         mov     ss,newss
  268.         mov     sp,newsp
  269.         sti
  270.         push    ax              ;store registers
  271.         push    bx
  272.         push    cx
  273.         push    dx
  274.         push    si
  275.         push    di
  276.         push    bp
  277.         push    ds
  278.         push    es
  279.         push    cs              ;set ds=cs
  280.         pop     ds
  281.         assume  ds:cseg
  282.         push    cs:tmpret       ;return
  283.         ret
  284. setup   endp
  285.  
  286. ;***********************************************************************
  287. ;shutdown routine for interrupt hook routines
  288. ; restores registers, switches stacks
  289. shutdown proc near
  290. ifdef   debug
  291.         public  shutdown
  292. endif
  293.         pop     cs:tmpret
  294.         pop     es              ;restore registers
  295.         pop     ds
  296.         assume ds:nothing
  297.         pop     bp
  298.         pop     di
  299.         pop     si
  300.         pop     dx
  301.         pop     cx
  302.         pop     bx
  303.         pop     ax
  304.         cli                     ;restore stack
  305.         mov     ss,cs:oldss
  306.         mov     sp,cs:oldsp
  307.         sti
  308.         push    cs:tmpret       ;return
  309.         ret
  310. shutdown endp
  311.  
  312. ;***********************************************************************
  313. ;add specified block to changes
  314. ;  entry: bx = psp of block, dx = length of block in paras
  315. addblock proc near
  316. ifdef   debug
  317.         public  addblock
  318. endif
  319.         assume  ds:cseg
  320.         call    addhdr          ;add a psp header block
  321.         call    addvecs         ;add blocks for each hooked vector
  322.         ret
  323. addblock endp
  324.  
  325. ;***********************************************************************
  326. ;add header for a psp block
  327. ;  entry: bx = psp of block, dx = length of block in paras
  328. ;  exit:  alters di
  329. addhdr  proc near
  330. ifdef   debug
  331.         public  addhdr
  332. endif
  333.         assume  ds:nothing
  334.         mov     di,nextchange
  335.         cmp     di,vsize-vrecsize       ;assure room for next record
  336.         ja      @@1
  337.         mov     word ptr cs:changevectors[di].id,pspid
  338.         mov     cs:changevectors[di].psp,bx
  339.         mov     cs:changevectors[di].len,dx
  340.         add     di,vrecsize
  341.         mov     nextchange,di
  342. @@1:    ret
  343. addhdr  endp
  344.  
  345. ;***********************************************************************
  346. ;add vector blocks for each hooked vector
  347. ;  entry: bx = psp of block, dx = length of block in paras
  348. ;  exit:  alters ax,cx,dx,si,di,bp
  349. addvecs proc    near
  350. ifdef   debug
  351.         public  addvecs
  352. endif
  353.         assume  ds:cseg
  354.         push    ds
  355.         add     dx,bx                   ;now dx points to end of block
  356.         mov     di,nextchange           ;cs:changevectors[di] -> output area
  357.         xor     si,si
  358.         mov     ds,si                   ;ds:si -> vectors
  359.         assume  ds:nothing
  360.         xor     cx,cx                   ;cx = vector counter
  361.         cld                             ;forward
  362.  
  363. @@1:    lodsw                           ;ax = vector offset
  364.         mov     bp,ax                   ;save vector offset
  365.         lodsw                           ;ax = vector segment
  366.         cmp     ax,bx                   ;is vector above low limit?
  367.         jb      @@2
  368.         cmp     ax,dx                   ;is vector below high limit?
  369.         jae     @@2
  370.         cmp     di,vsize-vrecsize       ;room for another entry?
  371.         ja      @@2
  372.         mov     cs:changevectors[di].vec,cx ;save entry for this vector
  373.         mov     cs:changevectors[di].veco,bp
  374.         mov     cs:changevectors[di].vecs,ax
  375.         add     di,vrecsize
  376. @@2:    inc     cx                      ;next vector
  377.         cmp     cx,0FFh
  378.         jbe     @@1
  379.  
  380.         mov     nextchange,di
  381.         pop     ds
  382.         assume  ds:cseg
  383.         ret
  384. addvecs endp
  385.  
  386. ;***********************************************************************
  387. ;find changeblock matching psp
  388. ;  entry: bx = psp to match
  389. ;  exit: si = matching block, or 0 if none
  390. ;        destroys dx
  391. matchpsp proc near
  392. ifdef   debug
  393.         public  matchpsp
  394. endif
  395.         assume  ds:cseg
  396.         mov     si,offset changevectors
  397.         mov     dx,si
  398.         add     dx,nextchange           ;dx = next unused spot in changevectors
  399. @@1:    cmp     si,dx                   ;end of table
  400.         jae     @@3
  401.         cmp     word ptr [si].id,pspid  ;psp indicator?
  402.         jnz     @@2                     ;jump if not
  403.         cmp     [si].psp,bx             ;matching psp?
  404.         jnz     @@2                     ;jump if not
  405.         ret                             ;else return with match
  406. @@2:    add     si,vrecsize
  407.         jmp     @@1
  408. @@3:    xor     si,si                   ;no match if here
  409.         ret
  410. matchpsp endp
  411.  
  412. ;***********************************************************************
  413. ;remove all blocks associated with psp at offset si
  414. ;  exit: alters cx,dx,si,di,es
  415. rempsp  proc near
  416. ifdef   debug
  417.         public  rempsp
  418. endif
  419.         assume  ds:cseg
  420.         mov     di,si                   ;save destination
  421.         add     si,vrecsize             ;move to next record
  422.         mov     dx,offset changevectors
  423.         add     dx,nextchange           ;dx = address of next unused
  424. @@1:    cmp     si,dx                   ;end of table?
  425.         jae     @@2                     ;jump if so
  426.         cmp     word ptr [si].id,pspid  ;next psp indicator?
  427.         je      @@2                     ;jump if so
  428.         add     si,vrecsize             ;next block
  429.         jmp     @@1                     ;and loop
  430. @@2:    mov     cx,dx
  431.         sub     cx,si
  432.         shr     cx,1                    ;cx = words to move
  433.         push    cs
  434.         pop     es                      ;es = ds = cs
  435.         cld
  436.         rep     movsw                   ;copy down remaining blocks
  437.         sub     si,di
  438.         sub     nextchange,si           ;update nextchange
  439.         ret
  440. rempsp  endp
  441.  
  442. ;***********************************************************************
  443. ;open high memory for DOS 5
  444. ;exit: changes ax,bx
  445. openhigh proc near
  446. ifdef   debug
  447.         public  openhigh
  448. endif
  449.         assume  ds:cseg
  450.         cmp     byte ptr dosver,5       ;DOS 5?
  451.         jne     @@2
  452.         mov     ax,5802H                ;get UMB link status
  453.         int     21H
  454.         jnc     @@1
  455.         xor     al,al
  456. @@1:    xor     ah,ah
  457.         mov     umbstat,ax              ;save status
  458.  
  459. ;save last segment in low memory, which DOS will overwrite
  460.         push    cx
  461.         push    si
  462.         push    di
  463.         push    ds
  464.         push    es
  465.         xor     si,si
  466.         mov     ds,topseg               ;ds:si -> region to buffer
  467.         push    cs
  468.         pop     es                      ;es = cs
  469.         mov     di,offset mcbbuf        ;es:di -> our buffer
  470.         mov     cx,8                    ;buffer 8 words
  471.         cld
  472.         rep     movsw
  473.         pop     es
  474.         pop     ds
  475.         pop     di
  476.         pop     si
  477.         pop     cx
  478.  
  479.         mov     ax,5803H
  480.         mov     bx,1
  481.         int     21H                     ;open high memory if possible
  482. @@2:    ret
  483. openhigh endp
  484.  
  485. ;***********************************************************************
  486. ;restore high memory link for DOS 5
  487. resthigh proc near
  488. ifdef   debug
  489.         public  resthigh
  490. endif
  491.         assume  ds:cseg
  492.         cmp     byte ptr dosver,5       ;DOS 5?
  493.         jne     @@1
  494.         mov     ax,5803H
  495.         mov     bx,umbstat
  496.         int     21H
  497.  
  498. ;restore last segment in low memory, which DOS overwrote
  499.         push    cx
  500.         push    si
  501.         push    di
  502.         push    es
  503.         mov     si,offset mcbbuf
  504.         mov     es,topseg
  505.         xor     di,di
  506.         mov     cx,8                    ;buffer 8 words
  507.         cld
  508.         rep     movsw
  509.         pop     es
  510.         pop     di
  511.         pop     si
  512.         pop     cx
  513.  
  514. @@1:    ret
  515. resthigh endp
  516.  
  517. ;***********************************************************************
  518. ;resident portion above, temporary portion below
  519. ;***********************************************************************
  520.                 align 16
  521. emesg   db      'Cannot install WATCH more than once....',13,10,36
  522. mesg    db      'WATCH 3.1, Copyright 1991 TurboPower Software',13,10
  523.         db      'Installed successfully',13,10,36
  524. pname   db      'TSR WATCHER'
  525. plen    equ     $-pname                 ;length of string
  526.  
  527. ;***********************************************************************
  528. ;add dummy changeblocks for all psps already resident
  529. adddummypsp proc near
  530. ifdef   debug
  531.         public  adddummypsp
  532. endif
  533.         assume  ds:cseg
  534.         call    openhigh                ;open high memory if available
  535.         mov     ah,52H
  536.         int     21H                     ;get DOS list of lists
  537.         mov     ax,es:[bx-2]            ;get first MCB segment
  538.         mov     firstmcb,ax             ;save it for use later too
  539.         push    ds
  540.         assume  ds:nothing
  541.  
  542. @@1:    mov     ds,ax
  543.         mov     bx,ds:[0001h]           ;bx = psp of block
  544.         mov     dx,ds:[0003h]           ;dx = len of block
  545.         inc     ax
  546.         cmp     ax,bx                   ;does psp = mcb+1?
  547.         jne     @@2                     ;jump if not
  548.         cmp     ax,newss                ;does psp = WATCH itself?
  549.         je      @@2                     ;jump if so
  550.         call    addhdr                  ;add a header for this block
  551. @@2:    cmp     byte ptr ds:[0000h],'Z' ;end of chain
  552.         je      @@3
  553.         add     ax,dx
  554.         jmp     @@1
  555.  
  556. @@3:    pop     ds
  557.         assume  ds:cseg
  558.         call    resthigh                ;restore high memory
  559.         ret
  560. adddummypsp endp
  561.  
  562. ;***********************************************************************
  563. init    proc    near
  564. ifdef   debug
  565.         public  init
  566. endif
  567.         assume  ds:cseg
  568.  
  569. ;use int 21h test to check for previous installation
  570.         mov     ax,7761H                ;special id function
  571.         int     21H
  572.         jc      @@1                     ;not installed if function fails
  573.         cmp     ax,6177H
  574.         jnz     @@1                     ;not installed if id code not returned
  575.  
  576. ;error exit
  577.         mov    dx,offset emesg          ;error message
  578.         mov    ah,09H
  579.         int    21H                      ;DOS print string
  580.         mov    ax,4C01H                 ;exit with error
  581.         int    21H
  582.  
  583. ;not already installed
  584. @@1:    mov    dx,offset mesg           ;success message
  585.         mov    ah,09H
  586.         int    21H                      ;DOS print string
  587.  
  588. ;initialize location of WATCH stack
  589.         mov     newsp,newstackpos+ssize
  590.         mov     newss,cs                ;stack seg is code seg
  591.  
  592. ;put an id label at offset 80H to allow other programs to recognize WATCH
  593.         mov     cx,plen                 ;length of name string
  594.         mov     si,offset pname         ;offset of name string
  595.         mov     di,offset cmdline       ;offset of DOS command line
  596.         cld                             ;transfer in forward direction
  597.         mov     al,cl
  598.         stosb                           ;store length byte first
  599.         rep     movsb                   ;transfer characters
  600.  
  601. ;get DOS version
  602.         mov     ax,3000h
  603.         int     21H
  604.         mov     dosver,ax
  605.  
  606. ;get top of memory segment
  607.         int     12H
  608.         mov     cl,6
  609.         shl     ax,cl
  610.         dec     ax
  611.         mov     topseg,ax
  612.  
  613. ;add psp records for all blocks already resident
  614.         call    adddummypsp
  615.  
  616. ;relocate ourselves out of the way of the resident tables
  617.         push    cs
  618.         pop     es
  619.         mov     di,newloc+10H
  620.         push    di                      ;will act as a return address
  621.         mov     si,offset @@2
  622.         mov     cx,@@3-@@2
  623.         rep     movsb                   ;move code
  624.         ret                             ;"return" to the relocated code
  625.  
  626. ;store image of original vector table (overwrites messages and non-res code)
  627. @@2:    mov     di,origvectors
  628.         push    ds
  629.         xor     si,si                   ;offset 0
  630.         mov     ds,si                   ;source address segment 0
  631.         mov     cx,200H                 ;512 words to store
  632.         rep     movsw                   ;copy vectors to our table
  633.         pop     ds
  634.  
  635. ;store current int 21 and 27 vectors
  636.         mov     ax,3527H
  637.         int     21H
  638.         mov     old27,bx
  639.         mov     old27[2],es
  640.         mov     ax,3521H
  641.         int     21H
  642.         mov     old21,bx
  643.         mov     old21[2],es
  644.  
  645. ;install new vectors
  646.         mov    ax,2527H
  647.         mov    dx,offset int27h
  648.         int    21H
  649.         mov    ax,2521H
  650.         mov    dx,offset int21h
  651.         int    21H
  652.  
  653. ;terminate and stay resident
  654.         mov    dx,newloc
  655.         add    dx,15
  656.         mov    cl,4
  657.         shr    dx,cl
  658.         mov    ax,3100H         ;return success code
  659.         int    21H              ;note WATCH will track itself
  660. @@3:
  661. init    endp
  662.  
  663. cseg    ends
  664.         end     pentry
  665.