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