home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / Pascal / TSRSRC30.ZIP / WATCH.ASM < prev    next >
Encoding:
Assembly Source File  |  1991-10-15  |  22.7 KB  |  647 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. ; written for 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. ;==============================================================================
  20. ;
  21. Cseg    segment public para
  22.         assume  cs:Cseg, ds:nothing, es:nothing, ss:nothing
  23.  
  24.         org     080H
  25. cmdline label   byte                 ;pointer to command line
  26.  
  27.         org     100H
  28. comentry:
  29.         jmp     init
  30.  
  31. ;put the following in WATCH.MAP to update MEMU.PAS
  32. public bmesg,changevectors,origvectors,currvectors,nextchange
  33.  
  34. ;the following are useful when debugging
  35. ;public newint16,setup,shutdown,pspmatch,pspremove,dealloc
  36. ;public checkvec,vechdr,wrchg,cmpvec,savevec
  37. ;public stb21,stb27,st21idx,st27idx
  38.  
  39. ;******************************************************************************
  40. ;resident data structures not part of COM file
  41. changevectors   =       offset bmesg            ;data area overwrites bmesg & beyond
  42. vrecsize        equ     8                       ;number of bytes per vector change record
  43. maxchanges      equ     128                     ;maximum number of vector changes
  44. vsize           equ     maxchanges*vrecsize     ;size of vector change area in bytes
  45.  
  46. ;vector table buffers
  47. origvectors     equ     offset changevectors+vsize ;location of original vector table
  48. veclen          equ     400H                    ;size of vector table in bytes
  49. currvectors     equ     origvectors+veclen      ;location of current vector table
  50. newstackpos     equ     currvectors+veclen      ;location of newstack
  51. ssize           equ     0080H                   ;number of bytes in temporary stack
  52. newloc          equ     newstackpos+ssize       ;location for relocated installation code
  53.  
  54. ;******************************************************************************
  55. ;data structures part of COM file
  56.                 even
  57. nextchange      dw      0               ;next position to write in data area
  58. ourcs           dw      ?               ;value of cs at runtime
  59.  
  60. ;temporary stack used by interrupt handler
  61. newss           dw      ?               ;segment of our temporary stack
  62. newsp           dw      ?               ;initial stack pointer
  63. tmpret          dw      ?               ;used while switching stacks
  64.  
  65. ;information saved about the calling program
  66. oldss           dw      ?               ;stack segment
  67. oldsp           dw      ?               ;stack pointer
  68.  
  69. ;previous interrupt handlers
  70. kbd_int         label dword
  71. old16           dw 2 dup (?)            ;old int16 vector
  72. dos_int         label dword
  73. old21           dw 2 dup (?)            ;old int21 vector
  74.  
  75. ;int16H function call for id check
  76. getid           equ     'wa'            ;function code for int16
  77. chkid           equ     'WA'            ;returned by int16 getid check
  78.  
  79. ;id code for a PSP data block
  80. pspid           equ     0FFFFH          ;id used to indicate a PSP block
  81.  
  82. ;***********************************************************************
  83. ;interrupt handler for int16
  84. ;used only to avoid reinstallation
  85. newint16 proc  near
  86.         assume  ds:nothing
  87.         pushf                   ;save application flags
  88.         sti
  89.         cmp     ax,getid        ;see if our id function
  90.         jne     ex16            ;no, pass on to previous int16
  91.         mov     ax,chkid        ;return id code
  92.         popf
  93.         iret                    ;back to caller
  94. ex16:   popf
  95.         jmp     kbd_int         ;transfer control to the previous int16
  96. newint16 endp
  97.  
  98. ;***********************************************************************
  99. ;int 21 handling stubs
  100. ;code counts on exact byte sequence of each stub
  101. st21siz         equ     8               ;number of bytes in int 21 stub
  102. st21max         equ     32              ;maximum times we can grab int 21
  103. st21idx         dw      offset stb21    ;offset of current stub in use
  104. st21lim         dw      offset stb21+st21siz*(st21max-1) ;last usable stub
  105.  
  106. stb21   label byte
  107. REPT    st21max
  108.         assume  ds:nothing
  109.         call    int21work
  110. db      0EAh,0,0,0,0            ;jmp far immediate
  111. ENDM
  112.  
  113. ;***********************************************************************
  114. ;int 27 handling stubs
  115. ;code counts on exact byte sequence of each stub
  116. st27siz         equ     8               ;number of bytes in int 27 stub
  117. st27max         equ     32              ;maximum times we can grab int 27
  118. st27idx         dw      offset stb27    ;offset of current stub in use
  119. st27lim         dw      offset stb27+st27siz*(st27max-1) ;last usable stub
  120.  
  121. stb27   label byte
  122. REPT    st27max
  123.         assume  ds:nothing
  124.         call    int27work
  125. db      0EAh,0,0,0,0            ;jmp far immediate
  126. ENDM
  127.  
  128. ;***********************************************************************
  129. ;put the interrupt address in es:bx into stub at di
  130. setstb  proc near
  131.         mov     cs:[di+4],bx
  132.         mov     cs:[di+6],es
  133.         ret
  134. setstb  endp
  135.  
  136. ;***********************************************************************
  137. ;clear the call to int2?work in stub at di
  138. clrstb  proc near
  139.         mov     word ptr cs:[di],9090H
  140.         mov     byte ptr cs:[di+2],90H
  141.         ret
  142. clrstb  endp
  143.  
  144. ;***********************************************************************
  145. ;do the real work of our int21 handler
  146. ;(control transferred from int 21 stub)
  147. ;note: if we run out of stub space, WATCH effectively disables itself
  148. int21work proc near
  149.         assume ds:nothing
  150.         pushf                    ;save flags
  151.  
  152. ;check to see whether another program has grabbed int 21 or 27
  153.         push    ax
  154.         push    es
  155.  
  156.         xor     ax,ax
  157.         mov     es,ax
  158.         mov     ax,ourcs
  159.         cmp     es:[4*21H+2],ax  ;do we own int 21?
  160.         jnz     grab             ;if not, grab it back
  161.         cmp     es:[4*27H+2],ax  ;do we own int 27?
  162.         jz      haveem           ;we're done if so
  163.  
  164. ;we need to grab at least one interrupt
  165. grab:   push    bx
  166.         push    dx
  167.         push    di
  168.         push    ds
  169.  
  170.         push    cs
  171.         pop     ds
  172.         assume  ds:cseg
  173.  
  174.         mov     ax,es:[4*21H+2]  ;get current int 21 segment
  175.         cmp     ax,ourcs         ;do we own int 21?
  176.         je      have21           ;jump if so
  177.         mov     bx,es:[4*21H]    ;get current int 21 offset
  178.         mov     es,ax            ;es:bx = current int 21
  179.         mov     di,st21idx
  180.         call    clrstb           ;turn existing stub into straight jump
  181.         cmp     di,st21lim       ;room for more stubs?
  182.         jae     have21           ;forget it if no more room
  183.         add     di,st21siz       ;move to next stub
  184.         mov     st21idx,di
  185.         call    setstb           ;have next stub jump to current int 21
  186.         mov     dx,di
  187.         mov     ax,2521H
  188.         pushf
  189.         call    dos_int
  190.  
  191. have21: xor     ax,ax
  192.         mov     es,ax
  193.         mov     ax,es:[4*27H+2]  ;get current int 27 segment
  194.         cmp     ax,ourcs         ;do we own int 27?
  195.         je      have27           ;jump if so
  196.         mov     bx,es:[4*27H]    ;get current int 27 offset
  197.         mov     es,ax            ;es:bx = current int 27
  198.         mov     di,st27idx
  199.         call    clrstb           ;turn existing stub into straight jump
  200.         cmp     di,st27lim       ;room for more stubs?
  201.         jae     have27           ;forget it if no more room
  202.         add     di,st27siz       ;move to next stub
  203.         mov     st27idx,di
  204.         call    setstb           ;have next stub jump to current int 27
  205.         mov     dx,di
  206.         mov     ax,2527H
  207.         pushf
  208.         call    dos_int
  209.  
  210. have27: pop     ds
  211.         assume  ds:nothing
  212.         pop     di
  213.         pop     dx
  214.         pop     bx
  215.  
  216. haveem: pop     es
  217.         pop     ax
  218.  
  219. ;trap DOS functions 31 and 49
  220.         cmp     ah,31H           ;terminate and stay resident call?
  221.         jne     chk49
  222.         call    checkvec         ;call routine to handle stayres calls
  223.         jmp     short ex21
  224.  
  225. chk49:  cmp     ah,49H           ;deallocate memory call?
  226.         jne     ex21
  227.         call    dealloc          ;call routine to handle program unloading
  228.  
  229. ex21:   popf
  230.         ret
  231. int21work endp
  232.  
  233. ;***********************************************************************
  234. ;do the real work of our int27 handler
  235. ;(control transferred from int 27 stub)
  236. int27work proc near
  237.         assume ds:nothing
  238.         pushf
  239.         push   dx
  240.         add    dx,15            ;pass size of block in paras to checkvec
  241.         shr    dx,1
  242.         shr    dx,1
  243.         shr    dx,1
  244.         shr    dx,1
  245.         call   checkvec
  246.         pop    dx
  247.         popf
  248.         ret
  249. int27work endp
  250.  
  251. ;***********************************************************************
  252. ;procedure dealloc
  253. ;  checks whether deallocated memory is a PSP we're tracking
  254. ;  if so, deletes that PSP block from our change table
  255. ;  stores a new vector buffer
  256. dealloc proc    near
  257.         assume ds:nothing
  258.         call    setup
  259.         mov     bx,es           ;save segment being deallocated in bx
  260.         call    pspmatch        ;return si=0 if bx not a psp in changetable
  261.         cmp     si,0
  262.         je      dedone
  263.         call    pspremove       ;remove found psp from changetable
  264.         mov     di,currvectors  ;save the new version of the vector table
  265.         call    savevec
  266. dedone: call    shutdown
  267.         ret
  268. dealloc endp
  269.  
  270. ;***********************************************************************
  271. ;procedure checkvec
  272. ;  compares vectors to previous installation
  273. ;  stores a new vector buffer
  274. ;  on entry dx=paras to keep
  275. ;  on exit  dx=top segment going resident
  276. checkvec proc  near
  277.         assume ds:nothing
  278.         call    setup
  279.         mov     ah,51H           ;get current PSP in bx
  280.         pushf
  281.         call    dos_int
  282.         add     dx,bx            ;dx = segment beyond that going resident
  283.         call    vechdr           ;store the PSP segment of the program going resident
  284.         call    cmpvec           ;scan the vector table looking for changes from our buffer
  285.         mov     di,currvectors   ;save the new version of the vector table
  286.         call    savevec
  287.         call    shutdown
  288.         ret
  289. checkvec endp
  290.  
  291. ;***********************************************************************
  292. ;setup routine for checkvec and dealloc
  293. ; switches stacks
  294. ; saves registers
  295. ; sets ds=cs
  296. setup   proc    near
  297.         pop     cs:tmpret       ;save return address as we switch stacks
  298.  
  299.         mov     oldss,ss        ;save current stack
  300.         mov     oldsp,sp
  301.  
  302.         cli                     ;switch to our stack
  303.         mov     ss,newss
  304.         mov     sp,newsp
  305.         sti
  306.  
  307.         push    ax              ;store registers
  308.         push    bx
  309.         push    cx
  310.         push    dx
  311.         push    si
  312.         push    di
  313.         push    ds
  314.         push    es
  315.  
  316.         mov     ax,cs
  317.         mov     ds,ax           ;ds = cs
  318.  
  319.         push    cs:tmpret
  320.         ret
  321. setup   endp
  322.  
  323. ;***********************************************************************
  324. ;shutdown routine for checkvec and dealloc
  325. ; saves current vector image
  326. ; restores registers
  327. ; switches stacks
  328. shutdown proc near
  329.         pop     cs:tmpret
  330.  
  331.         pop     es              ;restore registers
  332.         pop     ds
  333.         pop     di
  334.         pop     si
  335.         pop     dx
  336.         pop     cx
  337.         pop     bx
  338.         pop     ax
  339.  
  340.         cli                     ;restore stack
  341.         mov     ss,cs:oldss
  342.         mov     sp,cs:oldsp
  343.         sti
  344.  
  345.         push    cs:tmpret
  346.         ret
  347. shutdown endp
  348.  
  349. ;***********************************************************************
  350. ;procedure pspmatch
  351. ; returns si pointing to start of psp rec if bx is found, else si=0
  352. ; entry: bx=PSP to match
  353. pspmatch proc near
  354.         assume  ds:cseg
  355.         mov     si,offset changevectors ;index into changevectors array
  356.         mov     dx,si
  357.         add     dx,nextchange       ;dx = next available spot in changevectors
  358. matloop:cmp     si,dx               ;end of table?
  359.         jae     matdone
  360.         cmp     word ptr [si],pspid ;psp indicator?
  361.         jnz     matnext
  362.         cmp     [si+2],bx           ;matching psp?
  363.         jnz     matnext
  364.         ret                         ;return matching si
  365. matnext:add     si,vrecsize
  366.         jmp     matloop
  367.  
  368. matdone:xor     si,si               ;return si=0
  369.         ret
  370. pspmatch endp
  371.  
  372. ;***********************************************************************
  373. ;procedure pspremove
  374. ;removes psp started at index si
  375. pspremove proc near
  376.         assume  ds:cseg
  377.         mov     di,si               ;save destination
  378.         add     si,vrecsize         ;move to next record
  379.         mov     dx,offset changevectors
  380.         add     dx,nextchange       ;dx = address of next available
  381. remloop:cmp     si,dx               ;end of table?
  382.         jae     remend
  383.         cmp     word ptr [si],pspid ;psp indicator?
  384.         je      remend
  385.         add     si,vrecsize
  386.         jmp     remloop
  387.  
  388. remend: mov    cx,dx
  389.         sub    cx,si                ;cx = bytes to move
  390.         shr    cx,1                 ;cx = words to move
  391.         push   ds
  392.         pop    es                   ;assure es=ds=cs
  393.         cld
  394.         rep    movsw
  395.         sub    si,di                ;update nextchange
  396.         sub    nextchange,si
  397.         ret
  398. pspremove endp
  399.  
  400. ;**************************************************************************
  401. ;procedure vechdr
  402. ;  writes a header to the vector data area for this new TSR
  403. ;  on entry bx has PSP of the new TSR, dx has top segment of TSR
  404. ;  trashes di
  405. vechdr proc near
  406.        assume ds:cseg
  407.        cmp      nextchange,vsize-vrecsize ;assure room for next record
  408.        ja       vecex                     ;ignore if no room
  409.        mov      di,nextchange             ;index into changevectors array
  410.        mov      word ptr [di+changevectors],pspid  ;store id word
  411.        mov      word ptr [di+changevectors+2],bx   ;store PSP value
  412.                                           ;two words in record left unitialized
  413.        add      nextchange,vrecsize       ;move to next data element
  414. vecex: ret
  415. vechdr endp
  416.  
  417. ;**************************************************************************
  418. ;procedure wrchg
  419. ;  writes information about changed vectors to the data area
  420. ;  on entry:
  421. ;    cx has changed vector number
  422. ;    ax:bp contains vector value
  423. ;  on exit:
  424. ;    flags changed
  425. wrchg  proc     near
  426.        assume   ds:nothing
  427.        cmp      nextchange,vsize-vrecsize ;assure room for next record
  428.        ja       wrcex
  429.        push     di
  430.        mov      di,offset changevectors
  431.        add      di,nextchange                   ;index into changevectors array
  432.        mov      cs:[di],cx                      ;store interrupt vector number
  433.        mov      cs:[di+2],bp                    ;store vector offset
  434.        mov      cs:[di+4],ax                    ;store segment
  435.                                                 ;one word in record left unused
  436.        add      nextchange,vrecsize             ;move to next data element
  437.        pop      di
  438. wrcex: ret
  439. wrchg  endp
  440.  
  441. ;**************************************************************************
  442. ;procedure cmpvec
  443. ;  compares vectors in buffer to those in use
  444. ;  writes numbers of those different to data area
  445. ;  doesn't write those that point outside of the TSR
  446. ;  on entry:
  447. ;    bx has base of TSR, dx has top of TSR
  448. ;  on exit:
  449. ;    ax,cx,si,di destroyed
  450. ;    flags changed
  451. cmpvec  proc   near
  452.         assume ds:nothing
  453.         push    bp
  454.         push    ds
  455.         push    es
  456.  
  457.         xor     si,si           ;source offset 0
  458.         mov     ds,si           ;source address segment 0
  459.         mov     ax,cs
  460.         mov     es,ax
  461.         xor     cx,cx           ;vector counter
  462.         mov     di,currvectors  ;destination offset
  463.         cld                     ;upward direction
  464.  
  465. nexvec: cmpsw                   ;compare offsets
  466.         je      cmpseg          ;compare segments if offsets equal
  467.         cmpsw                   ;compare next word, ignore result
  468.         jmp     short cmprng    ;make sure vector points into program
  469. cmpseg: cmpsw                   ;compare segments
  470.         je      vecinc          ;jump if equal
  471. cmprng: mov     bp,ds:[si-4]    ;save vector offset in bp
  472.         mov     ax,ds:[si-2]    ;save vector segment in ax
  473.         cmp     ax,bx           ;lower than base of TSR?
  474.         jb      cmp21           ;jump if so
  475. cmprng2:cmp     ax,dx           ;above top of TSR?
  476.         jae     cmp21           ;jump if so
  477.         call    wrchg           ;write changed vector
  478.         jmp     short vecinc
  479. cmp21:  cmp     cl,21H          ;checking int 21?
  480.         jne     vecinc          ;jump if not
  481.         cmp     ax,ourcs        ;does int21 point to us?
  482.         jne     vecinc          ;jump if not
  483.         push    di
  484.         mov     di,st21idx
  485.         mov     bp,cs:[di+4]    ;save current offset in bp
  486.         mov     ax,cs:[di+6]    ;save current segment in ax
  487.         pop     di
  488.         cmp     ax,bx           ;lower than base of TSR?
  489.         jb      vecinc          ;jump if so
  490.         cmp     ax,dx           ;above top of TSR?
  491.         jae     vecinc          ;jump if so
  492.         call    wrchg           ;write changed vector
  493.  
  494. vecinc: inc     cx              ;next vector number
  495.         cmp     cx,00FFH
  496.         jbe     nexvec          ;continue until 256 vectors checked
  497.  
  498.         pop     es
  499.         pop     ds
  500.         pop     bp
  501.         ret
  502. cmpvec  endp
  503.  
  504. ;**************************************************************************
  505. ;procedure savevec
  506. ;  saves image of interrupt vectors
  507. ;  on entry:
  508. ;    di has destination offset
  509. ;  on exit:
  510. ;    ax,cx,si,di destroyed
  511. ;    flags changed
  512. savevec proc   near
  513.         assume ds:nothing
  514.         push    ds
  515.         push    es
  516.         xor     si,si           ;offset 0
  517.         mov     ds,si           ;source address segment 0
  518.         mov     ax,cs
  519.         mov     es,ax           ;destination always in this code segment
  520.         mov     cx,200H         ;512 integers to store
  521.         cld                     ;copy up
  522.         rep     movsw           ;copy vectors to our table
  523.         pop     es
  524.         pop     ds
  525.         ret
  526. savevec endp                    ;of proc savevec
  527.  
  528. ;**************************************************************************
  529. ;resident portion above, temporary portion below
  530. ;**************************************************************************
  531.  
  532.                align 16
  533. bmesg   db     'Cannot install WATCH more than once....',13,10,36
  534. mesg    db     'WATCH 3.0, Copyright 1991 TurboPower Software',13,10
  535. mesg2   db     'Installed successfully',13,10,36
  536. pname   db     'TSR WATCHER'
  537. plen    equ    $-pname             ;length of string
  538.  
  539. ;**************************************************************************
  540. init    proc   near
  541.         assume ds:cseg
  542.  
  543. ;use int 16h test to check for previous installation
  544.         mov     ax,getid        ;int16h diagnostic request
  545.         int     16h             ;now, ax=chkid if installed
  546.         cmp     ax,chkid        ;TSR already installed?
  547.         jne     success         ;no - jump if not installed
  548.  
  549. ;error exit
  550.         mov    dx,offset bmesg  ;error message
  551.         mov    ah,09H
  552.         int    21H              ;DOS print string
  553.         mov    ax,4C01H         ;exit with error
  554.         int    21H
  555.  
  556. ;print a success message
  557. success: mov    dx,offset mesg  ;start of message to write
  558.          mov    ah,09H
  559.          int    21H             ;DOS print string
  560.  
  561. ;relocate ourselves out of the way of the vector tables
  562.         mov     ax,cs
  563.         mov     es,ax
  564.         mov     di,newloc+10H
  565.         push    di                    ;will act as a return address
  566.         mov     si,offset newstk
  567.         mov     cx,lastcode-newstk
  568.         rep     movsb                 ;move code
  569.         ret                           ;"return" to the relocated code
  570.  
  571. ;initialize location of WATCH stack
  572. newstk: mov     newsp,newstackpos+ssize
  573.         mov     newss,cs        ;stack seg is code seg
  574.  
  575. ;get int 16H vector
  576.         mov    ax,3516H         ;GetVector DOS function call
  577.         int    21H
  578.         mov    old16,bx         ;store first word of old21
  579.         mov    old16[2],es      ;store second word
  580.  
  581. ;get int 27H vector
  582.         mov    ax,3527H         ;GetVector DOS function call
  583.         int    21H
  584.         mov    ax,offset setstb
  585.         mov    di,st27idx
  586.         call   ax               ;save vector in first stub
  587.  
  588. ;get int 21H vector
  589.         mov    ax,3521H         ;GetVector DOS function call
  590.         int    21H
  591.         mov    old21,bx         ;store first word of old21 (offset)
  592.         mov    old21[2],es      ;store second word (segment)
  593.         mov    ax,offset setstb
  594.         mov    di,st21idx
  595.         call   ax               ;save vector in first stub
  596.  
  597. ;put an id label at offset 80H to allow other programs to recognize WATCH
  598.         mov    ax,cs
  599.         mov    es,ax
  600.         mov    cx,plen          ;length of name string
  601.         mov    si,offset pname  ;offset of name string
  602.         mov    di,offset cmdline ;offset of DOS command line
  603.         cld                     ;transfer in forward direction
  604.         mov    al,cl
  605.         stosb                   ;store length byte first
  606.         rep    movsb            ;transfer characters
  607.  
  608. ;store image of original vector table (overwrites messages)
  609.         mov    di,origvectors
  610.         mov    ax,offset savevec
  611.         call   ax               ;absolute call works as code is moved
  612.  
  613. ;store it again into the current vector table
  614.         mov    di,currvectors
  615.         mov    ax,offset savevec
  616.         call   ax               ;absolute call works as code is moved
  617.  
  618. ;install the new vectors
  619.         mov    ax,2516H
  620.         mov    dx,offset newint16
  621.         int    21H
  622.  
  623.         mov    ax,2527H
  624.         mov    dx,offset stb27
  625.         int    21H
  626.  
  627.         mov    ax,2521H
  628.         mov    dx,offset stb21
  629.         int    21H
  630.  
  631. ;save cs in a convenient place
  632.         mov    ourcs,cs
  633.  
  634. ;terminate and stay resident
  635.         mov    dx,newloc
  636.         add    dx,000FH
  637.         mov    cl,4
  638.         shr    dx,cl
  639.         mov    ax,3100H        ;return success code
  640.         pushf
  641.         call   dos_int         ;don't log vectors WATCH itself takes over
  642. lastcode:
  643. init    endp
  644.  
  645. Cseg    ends
  646.         end     ComEntry
  647.