home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / sysutl / sysprof3.arc / ORIGINAL.ARC / SYS_PROF.ASM < prev   
Assembly Source File  |  1988-06-16  |  30KB  |  780 lines

  1. ;-----------------------------------------------------------------------------;
  2. ;                                                                             ;
  3. ;                                  Listing 1                                  ;
  4. ;                                                                             ;
  5. ;   NAME : SYS_PROF                                                           ;
  6. ;                                                                             ;
  7. ;   DATE : March 24, 1988                                                     ;
  8. ;                                                                             ;
  9. ;   AUTHOR : (C) Copyright 1988 G. Kent Cobb - All Rights Reserved            ;
  10. ;                                                                             ;
  11. ;   DESCRIPTION :                                                             ;
  12. ;       This is the terminate-and-stay-resident portion of a system profiler. ;
  13. ;       It installs several interrupt handlers, which monitor the occurrences ;
  14. ;       and duration of a number of software interrupts.                      ;
  15. ;                                                                             ;
  16. ;-----------------------------------------------------------------------------;
  17.  
  18. ;----------------------------------------------------------------------------;
  19. ;                              Interrupt numbers                             ;
  20. ;----------------------------------------------------------------------------;
  21.  
  22. TIMER_INTERRUPT     EQU 1CH
  23. TERMINATE           EQU 20H
  24. TERM_AND_STAY_RES   EQU 27H
  25. CONTROL_INTERRUPT   EQU 60H
  26.  
  27. ;----------------------------------------------------------------------------;
  28. ;                  MS-DOS functions (Interrupt 21H services)                 ;
  29. ;----------------------------------------------------------------------------;
  30.  
  31. DOS MACRO   OP
  32.     MOV AH,DOS_&OP
  33.     INT 21H
  34.     ENDM
  35.  
  36. DOS_DISPLAY_STRING  EQU 09H
  37. DOS_SET_INT_VECTOR  EQU 25H
  38. DOS_GET_INT_VECTOR  EQU 35H
  39.  
  40. ;----------------------------------------------------------------------------;
  41. ;   This is a list of all the interrupts that are intercepted by SYS_PROF.   ;
  42. ;----------------------------------------------------------------------------;
  43.  
  44. NUMBER_OF_INTERRUPTS        EQU 9
  45.  
  46. PRINT_SCREEN_INTERRUPT      EQU  5H
  47. VIDEO_INTERRUPT             EQU 10H
  48. DISK_INTERRUPT              EQU 13H
  49. COMM_INTERRUPT              EQU 14H
  50. KEYBOARD_INTERRUPT          EQU 16H
  51. PRINTER_INTERRUPT           EQU 17H
  52. DOS_FUNC_INTERRUPT          EQU 21H
  53. ABS_DISK_READ_INTERRUPT     EQU 25H
  54. ABS_DISK_WRITE_INTERRUPT    EQU 26H
  55.  
  56.  
  57. ;----------------------------------------------------------------------------;
  58. ;   These are the number of distinct services defined for each interrupt.    ;
  59. ;   The OCCURRENCES array contains two double words for each service, and    ;
  60. ;   two additional double words for each interrupt.  If an interrupt is      ;
  61. ;   generated with a service number that is out of range, the data for it    ;
  62. ;   will accumulate in this additional bin.                                  ;
  63. ;----------------------------------------------------------------------------;
  64.  
  65. PRINT_SCREEN_SERVICES       EQU 0
  66. VIDEO_SERVICES              EQU 20
  67. DISK_SERVICES               EQU 24
  68. COMM_SERVICES               EQU 4
  69. KEYBOARD_SERVICES           EQU 3
  70. PRINTER_SERVICES            EQU 3
  71. DOS_FUNC_SERVICES           EQU 99
  72. ABS_DISK_READ_SERVICES      EQU 0
  73. ABS_DISK_WRITE_SERVICES     EQU 0
  74.  
  75. ;-----------------------------------------------------------------------;
  76. ;   This macro defines the handling of the intercepted interrupts.  The ;
  77. ;   INT_NUM parameter that the macro expects is an index into the       ;
  78. ;   MAX_SERVICES and OFFSETS tables.                                    ;
  79. ;                                                                       ;
  80. ;   Interrupts 25H and 26H are handled in a manner which is very        ;
  81. ;   similar, but slightly different from the other interrupts.  If this ;
  82. ;   macro is invoked with a second parameter, code is included to       ;
  83. ;   provide the special handling that these interrupts require.         ;
  84. ;-----------------------------------------------------------------------;
  85.  
  86. PERFORM_INTERRUPT MACRO INT_NUM,SPECIAL
  87.  
  88. INTERRUPT_HANDLER&INT_NUM   PROC    FAR
  89.  
  90. ;   Turn interrupts back on.
  91.  
  92.         STI
  93.  
  94. ;   Save the existing interrupt and service numbers on the stack.
  95.  
  96.         PUSH CS:WORD PTR INTERRUPT
  97.  
  98. ;   Push the flags onto the stack now (before we execute any instructions which
  99. ;   might change them) in order to simulate an interrupt later. 
  100.  
  101.         PUSHF
  102.  
  103. ;   Save the value of WATCH on the stack while we're changing INTERRUPT and
  104. ;   SERVICE.
  105.  
  106.         PUSH CS:WATCH
  107.  
  108. ;   Turn accumulation off, set new INTERRUPT and SERVICE values, make sure 
  109. ;   the service number is valid, and then restore accumulation to its previous
  110. ;   state.
  111.  
  112.         MOV  CS:WATCH,0
  113.         MOV  CS:INTERRUPT,&INT_NUM
  114.         MOV  CS:SERVICE,AH
  115.         CALL VALIDATE_SERVICE
  116.         POP  CS:WATCH
  117.  
  118. ;   If accumulation is turned off, go straight to the real ISR.
  119.  
  120.         CMP  CS:WATCH,0
  121.         JE   READY_FOR_INTERRUPT&INT_NUM
  122.  
  123. ;   If accumulation is turned on, push a one onto the stack to tell the
  124. ;   ACCUMULATE routine which bin to increment, and then call it.
  125.  
  126.         PUSH CS:ONE
  127.         CALL ACCUMULATE
  128.  
  129. READY_FOR_INTERRUPT&INT_NUM:
  130.  
  131. ;   After tabulating occurrence data, execute the real ISR
  132.  
  133.         CALL CS:DWORD PTR OLD_INTERRUPT_VECTORS [ 4*(&INT_NUM-1) ]
  134.  
  135. ;   Interrupts 25H and 26H require special handling.  Since they leave the 
  136. ;   flags on the stack when they return control to the calling program, we 
  137. ;   have an extra word on the stack which must be popped.
  138.  
  139. IFNB    <SPECIAL>
  140.         POP  CS:EXTRA_FLAGS
  141. ENDIF
  142.  
  143. ;   On return, pop the interrupt and service numbers that were current before
  144. ;   this one.
  145.  
  146.         POP  CS:WORD PTR INTERRUPT
  147.  
  148. ;   For most interrupts, return with RET 2 rather than IRET.  This will 
  149. ;   preserve whatever treatment the real ISR uses for the flags.
  150.  
  151. IFB     <SPECIAL>
  152.         RET  2
  153.  
  154. ;   Interrupts 25H and 26H are special cases.  The calling program expects the
  155. ;   flags to still be on the stack, so we use RET instead.
  156.  
  157. ELSE
  158.         RET
  159. ENDIF
  160.  
  161. INTERRUPT_HANDLER&INT_NUM   ENDP
  162.  
  163.         ENDM
  164.  
  165.  
  166.  
  167. CODE_SEG    SEGMENT PUBLIC
  168.         ASSUME CS:CODE_SEG , DS:CODE_SEG
  169.     
  170. ;-----------------------------------------------------------------------;
  171. ;   This is the entry point for the program.  Control is immediately    ;
  172. ;   transferred to the initialization code, which is located in the     ;
  173. ;   portion of the program which does not remain resident.              ;
  174. ;-----------------------------------------------------------------------;
  175.  
  176.         ORG 100H                    ; COM FILE
  177.  
  178. JUMP_TO_INIT    PROC    FAR
  179.         JMP  INIT
  180. JUMP_TO_INIT    ENDP
  181.  
  182.  
  183. ;-----------------------------------------------------------------------------;
  184. ;   The handling for all nine intercepted interrupts is very similar, and is  ;
  185. ;   defined by the PERFORM_INTERRUPT macro.  This section contains the macro  ;
  186. ;   calls.                                                                    ;
  187. ;-----------------------------------------------------------------------------;
  188.  
  189. ;   Print screen interrupt
  190.  
  191.         PERFORM_INTERRUPT   1
  192.  
  193. ;   BIOS Video interrupt
  194.  
  195.         PERFORM_INTERRUPT   2
  196.  
  197. ;   BIOS Disk interrupt
  198.  
  199.         PERFORM_INTERRUPT   3
  200.  
  201. ;   BIOS Comm interrupt
  202.  
  203.         PERFORM_INTERRUPT   4
  204.  
  205. ;   BIOS Keyboard interrupt (16H)
  206.  
  207.         PERFORM_INTERRUPT   5
  208.  
  209. ;   BIOS Printer interrupt
  210.  
  211.         PERFORM_INTERRUPT   6
  212.  
  213. ;   DOS Function calls interrupt
  214.  
  215.         PERFORM_INTERRUPT   7
  216.  
  217. ;   The last two interrupts, 25H and 26H, require special handling since the
  218. ;   real ISRs do not pop the flags from the stack upon completion.  By passing
  219. ;   a second parameter to the PERFORM_INTERRUPT macro, the code to handle this 
  220. ;   will be included by the preprocessor when the macro is expanded.
  221.  
  222. ;   DOS Absolute disk read interrupt
  223.  
  224.         PERFORM_INTERRUPT   8   SPECIAL
  225.  
  226. ;   DOS Absolute disk write interrupt
  227.  
  228.         PERFORM_INTERRUPT   9   SPECIAL
  229.  
  230. ;-----------------------------------------------------------------------;
  231. ;   This routine is a piggyback ISR for interrupt 1C.  It tabulates     ;
  232. ;   the current interrupt and service numbers if WATCH is non-zero,     ;
  233. ;   and then executes the real ISR.                                     ;
  234. ;-----------------------------------------------------------------------;
  235.  
  236. NEW_TIMER   PROC    NEAR
  237.  
  238.         STI
  239.         CMP  CS:WATCH,0         ; check to see if we accumulate
  240.         JE   DO_OLD_INT1C       ; skip accumulate if 0
  241.         PUSH CS:ZERO            ; Push parameter onto stack
  242.         CALL ACCUMULATE         ; if not 0, accumulate data
  243.  
  244. DO_OLD_INT1C:
  245.         JMP  CS:DWORD PTR OLD_INT1C    ; jump to old interrupt 1C
  246.  
  247. NEW_TIMER   ENDP
  248.  
  249.  
  250. ;-----------------------------------------------------------------------;
  251. ;   This routine validates the service number that is stored in the     ;
  252. ;   memory location SERVICE.  For each interrupt, there is a maximum    ;
  253. ;   service number which is meaningful.  This routine obtains that      ;
  254. ;   number from the MAX_SERVICES array, and compares it to the value of ;
  255. ;   SERVICE.  If SERVICE is not between zero and MAX - 1, inclusive, it ;
  256. ;   is reset to MAX.  All services which are requested with invalid or  ;
  257. ;   unknown service numbers will then accumulate in an "Other" bin.     ;
  258. ;-----------------------------------------------------------------------;
  259.  
  260. VALIDATE_SERVICE    PROC    NEAR
  261.  
  262.         PUSH BX                 ; Save BX register
  263.  
  264.         MOV  BL,CS:INTERRUPT    ; Retrieve the interrupt number
  265.         XOR  BH,BH
  266.         DEC  BX                 ; Adjust indexing to zero-based
  267.         MOV  BL,CS:MAX_SERVICE[BX]
  268.                                 ; Get the maximum service number for this int
  269.         CMP  BL,CS:SERVICE      ; Compare to current service number
  270.         JG   SERVICE_VALID      ; If BL is greater, everything is OK
  271.         MOV  CS:SERVICE,BL      ; Otherwise, set the service to the maximum #
  272. SERVICE_VALID:
  273.         POP  BX                 ; Restore BX register and return
  274.         RET
  275.  
  276. VALIDATE_SERVICE    ENDP
  277.  
  278. ;-----------------------------------------------------------------------;
  279. ;   This routine increments a counter in the data table.  It uses the   ;
  280. ;   current interrupt and service numbers to determine the proper loca- ;
  281. ;   tion within the table.  Either of two counters may be incremented,  ;
  282. ;   depending on the value of the parameter passed in on the stack.  If ;
  283. ;   the routine is called from the timer tick ISR, the parameter will   ;
  284. ;   be zero, and the first of the two will be incremented.  If it is    ;
  285. ;   called from one of the software ISRs, the parameter will be one,    ;
  286. ;   and the second will be incremented instead.                         ;
  287. ;-----------------------------------------------------------------------;
  288.  
  289. ACCUMULATE  PROC    NEAR
  290.  
  291.         PUSH BP
  292.         MOV  BP,SP              ; Establish local stack frame
  293.  
  294.         PUSH AX
  295.         PUSH BX                 ; push registers
  296.  
  297. ;   Calculate offset into the table of occurrences.
  298.  
  299.         MOV  BL,CS:INTERRUPT    ; move code for interrupt currently being 
  300.                                 ;   serviced into bl
  301.         XOR  BH,BH              ; zero out bh
  302.         SHL  BX,1               ; Multiply by two since OFFSETS are words.
  303.         MOV  BX,CS:OFFSETS[BX]  ; Get the offset into the accumulation table
  304.         MOV  AL,CS:SERVICE      ; move code for service currently being
  305.                                 ;   performed into al
  306.         XOR  AH,AH              ; zero out ah
  307.         SHL  AX,1               ; multiply by 4 to convert number of 
  308.         SHL  AX,1               ;   double words to number of bytes
  309.         SHL  AX,1               ; multiply by 2 since there are two double 
  310.                                 ;   words for each service
  311.         ADD  BX,AX              ; add offset to get offset of data for this
  312.                                 ;   service
  313.         CMP  WORD PTR [BP+4],0  ; Is the parameter zero?
  314.         JE   INC_DOUBLE         ; If yes, increment the first double word
  315.         ADD  BX,4               ; But if not, increment the second
  316. INC_DOUBLE:
  317.         
  318.         INC  CS:WORD PTR [BX]   ; Increment low-order word
  319.         JNZ  NO_CARRY
  320.         ADD  BX,2               ; If counter rolls over, increment high-
  321.         INC  CS:WORD PTR [BX]   ;   order word also
  322.  
  323. NO_CARRY:
  324.  
  325.         POP  BX                 ; Restore registers
  326.         POP  AX
  327.  
  328.         POP  BP                 ; Restore old stack frame
  329.         RET  2
  330.  
  331. ACCUMULATE  ENDP
  332.  
  333. ;-----------------------------------------------------------------------;
  334. ;   This is the service routine for the SYS_PROF control interrupt.  It ;
  335. ;   provides the following services:                                    ;
  336. ;                                                                       ;
  337. ;                   AH=0 : Report on/off status in AX                   ;
  338. ;                   AH=1 : Turn accumulation off                        ;
  339. ;                   AH=2 : Turn accumulation on                         ;
  340. ;                   AH=3 : Return address of data table in ES:BX        ;
  341. ;                   AH=4 : Reset data table to zeroes                   ;
  342. ;                                                                       ;
  343. ;   These services are used by the PROFCTRL program to control the      ;
  344. ;   operations of SYS_PROF.                                             ;
  345. ;-----------------------------------------------------------------------;
  346.  
  347. CONTROL_ISR PROC    NEAR
  348.  
  349.         STI             ; Enable interrupts
  350.         PUSH CX         ; Save registers
  351.         PUSH DI
  352.         CMP  AH,0       ; Is AH equal to 0?
  353.         JG   AH_NOT_0   ; No, skip to next test
  354.  
  355. ;   If we get to this point, AH is zero, which indicates that we should
  356. ;   report the status of the accumulation flag.
  357.  
  358.         MOV  AX,CS:WATCH
  359.         JMP  CONTROL_COMPLETE
  360.  
  361. AH_NOT_0:
  362.  
  363.         CMP  AH,1       ; Is AH equal to 1?
  364.         JG   AH_NOT_1   ; No, skip to next test
  365.  
  366. ;   If we get to this point, AH is one, which indicates that accumulation
  367. ;   is to be turned off.
  368.  
  369.         MOV  CS:WATCH,0 ; Turn off accumulation
  370.         JMP  OK
  371.  
  372. AH_NOT_1:
  373.  
  374.         CMP  AH,2       ; Is AH equal to 2?
  375.         JG   AH_NOT_2   ; No, skip to next test
  376.  
  377. ;   If we get to this point, AH is two, which indicates that accumulation
  378. ;   is to be turned on.
  379.  
  380.         MOV  CS:WATCH,1 ; Turn accumulation on
  381.         JMP  OK
  382.  
  383. AH_NOT_2:
  384.  
  385.         CMP  AH,3       ; Is AH equal to 3?
  386.         JG   AH_NOT_3   ; No, skip to next test
  387.  
  388. ;   If we get to this point, AH is three, which indicates that the segmented
  389. ;   address of the data accumulation table should be returned in ES:BX.
  390.  
  391.         MOV  BX,CS
  392.         MOV  ES,BX              ; es = cs
  393.         MOV  BX,OFFSET OCCURRENCES
  394.                                 ; offset of data table
  395.         JMP  OK
  396.  
  397. AH_NOT_3:
  398.  
  399.         CMP  AH,4       ; Is AH equal to 4?
  400.         JG   BAD_VALUE  ; No, it must be invalid.
  401.  
  402. ;   If we get to this point, AH is four, which indicates that the data table
  403. ;   should be reset to zeroes.
  404.  
  405.         PUSH ES         ; Save current value of ES
  406.         MOV  CS:WATCH,0 ; Don't want to accumulate while we're re-initializing
  407.         MOV  AX,CS
  408.         MOV  ES,AX      ; Make es = cs in order to use STOSW instruction
  409.         MOV  DI,OFFSET OCCURRENCES
  410.                         ; DI is set to start of data table for same reason
  411.         MOV  CX,OFFSET END_OF_TABLE
  412.         SUB  CX,DI
  413.         SHR  CX,1       ; CX contains number of words to zero
  414.         CLD
  415.         XOR  AX,AX
  416.         REP  STOSW      ; Zero the data table
  417.         POP  ES         ; Restore ES
  418.         JMP  OK
  419.  
  420. BAD_VALUE:
  421.  
  422.         MOV  AH,0FFH    ; Set AH to -1 to indicate error
  423.         JMP  CONTROL_COMPLETE
  424.  
  425. OK:
  426.  
  427.         XOR  AH,AH      ; Set AH to 0 to indicate success
  428.  
  429. CONTROL_COMPLETE:
  430.  
  431.         POP  DI         ; Restore registers
  432.         POP  CX
  433.         IRET
  434.  
  435. CONTROL_ISR ENDP
  436.  
  437.  
  438.     
  439. ;-----------------------------------------------------------------------;
  440. ;                              DATA AREA                                ;
  441. ;-----------------------------------------------------------------------;
  442.  
  443. ;-----------------------------------------------------------------------;
  444. ;   This variable controls data accumulation.  Service requests and     ;
  445. ;   timer ticks are tabulated if it is non-zero.                        ;
  446. ;-----------------------------------------------------------------------;
  447.  
  448. WATCH       DW  0
  449.  
  450. ;-----------------------------------------------------------------------;
  451. ;   The indices of the interrupt and service currently being performed  ;
  452. ;   are stored in this location.                                        ;
  453. ;-----------------------------------------------------------------------;
  454.  
  455. INTERRUPT   DB  0
  456. SERVICE     DB  0
  457.  
  458. ;-----------------------------------------------------------------------;
  459. ;   This array is used to store the segmented addresses of all the real ;
  460. ;   interrupt service routines.  It is initialized by                   ;
  461. ;   REPLACE_SYSTEM_INTERRUPTS, and is used in the PERFORM_INTERRUPT     ;
  462. ;   macro.                                                              ;
  463. ;-----------------------------------------------------------------------;
  464.  
  465. OLD_INTERRUPT_VECTORS   DD  10 DUP(0)
  466.  
  467. ;-----------------------------------------------------------------------;
  468. ;   This table has one entry for each interrupt that is intercepted by  ;
  469. ;   SYS_PROF.  The entry for a particular interrupt contains the number ;
  470. ;   of distinct services that can be requested in AH.  The values in the;
  471. ;   table are checked by the VALIDATE_SERVICE routine to prevent        ;
  472. ;   corruption of the data tabulation process.                          ;
  473. ;-----------------------------------------------------------------------;
  474.  
  475. MAX_SERVICE DB  PRINT_SCREEN_SERVICES
  476.             DB  VIDEO_SERVICES
  477.             DB  DISK_SERVICES
  478.             DB  COMM_SERVICES
  479.             DB  KEYBOARD_SERVICES
  480.             DB  PRINTER_SERVICES
  481.             DB  DOS_FUNC_SERVICES
  482.             DB  ABS_DISK_READ_SERVICES
  483.             DB  ABS_DISK_WRITE_SERVICES
  484.  
  485. ;-----------------------------------------------------------------------;
  486. ;   This area is used to tabulate the number of request for each        ;
  487. ;   service, and the timer ticks that occur during each service.        ;
  488. ;-----------------------------------------------------------------------;
  489.  
  490. OCCURRENCES         LABEL   DWORD
  491. OTHER_BIN           DD  2                             DUP (0)
  492. PRINT_SCREEN_BIN    DD  2*(1+PRINT_SCREEN_SERVICES)   DUP (0)
  493. VIDEO_BIN           DD  2*(1+VIDEO_SERVICES)          DUP (0)
  494. DISK_BIN            DD  2*(1+DISK_SERVICES)           DUP (0)
  495. COMM_BIN            DD  2*(1+COMM_SERVICES)           DUP (0)
  496. KEYBOARD_BIN        DD  2*(1+KEYBOARD_SERVICES)       DUP (0)
  497. PRINTER_BIN         DD  2*(1+PRINTER_SERVICES)        DUP (0)
  498. DOS_FUNC_BIN        DD  2*(1+DOS_FUNC_SERVICES)       DUP (0)
  499. ABS_DISK_READ_BIN   DD  2*(1+ABS_DISK_READ_SERVICES)  DUP (0)
  500. ABS_DISK_WRITE_BIN  DD  2*(1+ABS_DISK_WRITE_SERVICES) DUP (0)
  501. END_OF_TABLE        LABEL   DWORD
  502.  
  503. ;-----------------------------------------------------------------------;
  504. ;   This is a table of offsets into the previous table.  It defines the ;
  505. ;   offset of the start of the data area for each interrupt.            ;
  506. ;-----------------------------------------------------------------------;
  507.  
  508. OFFSETS LABEL WORD
  509.             DW  OTHER_BIN 
  510.             DW  PRINT_SCREEN_BIN 
  511.             DW  VIDEO_BIN
  512.             DW  DISK_BIN
  513.             DW  COMM_BIN
  514.             DW  KEYBOARD_BIN
  515.             DW  PRINTER_BIN
  516.             DW  DOS_FUNC_BIN
  517.             DW  ABS_DISK_READ_BIN
  518.             DW  ABS_DISK_WRITE_BIN
  519.  
  520.  
  521.  
  522.  
  523. OLD_INT1C   EQU $           ; address of old timer interrupt
  524. OLD_OFS     DW  ?           ; offset of old timer interrupt
  525. OLD_SEG     DW  ?           ; segment of old timer interrupt
  526.  
  527. ZERO            DW  0
  528. ONE             DW  1
  529. EXTRA_FLAGS     DW  0
  530.  
  531. ;-----------------------------------------------------------------------;
  532. ;   This is the main routine of the initialization section.  It replaces;
  533. ;   several interrupt vectors, and then terminates, leaving the data    ;
  534. ;   tables and the interrupt service routines resident.                 ;
  535. ;-----------------------------------------------------------------------;
  536.  
  537.  
  538. INIT    PROC NEAR
  539.  
  540. ;   Use internal stack during initialization
  541.  
  542.         MOV  SP,OFFSET END_STACK
  543.  
  544. ;   Display copyright notice
  545.  
  546.         MOV  DX,OFFSET COPYRIGHT_NOTICE
  547.         DOS  DISPLAY_STRING
  548.  
  549. ;   Install interrupt handlers.
  550.  
  551.         CALL INSTALL_CONTROL_INTERRUPT
  552.         CALL REPLACE_TIMER
  553.         CALL REPLACE_SYSTEM_INTERRUPTS
  554.  
  555. ;   Terminate and stay resident
  556.  
  557.         MOV  AX,CS
  558.         MOV  DS,AX
  559.         MOV  DX,OFFSET INIT + 100H
  560.         INT  TERM_AND_STAY_RES
  561. INIT    ENDP
  562.  
  563.  
  564.  
  565. ;-----------------------------------------------------------------------;
  566. ;   This routine initializes the interrupt vector for the SYS_PROF      ;
  567. ;   control interrupt.  If it has been initialized previously (as       ;
  568. ;   indicated by a non-zero value), SYS_PROF will terminate without     ;
  569. ;   remaining resident.  This makes it possible to run SYS_PROF several ;
  570. ;   times in succession without taking up additional memory each time,  ;
  571. ;   and without checking beforehand to see if it is already resident.   ;
  572. ;-----------------------------------------------------------------------;
  573.  
  574. INSTALL_CONTROL_INTERRUPT   PROC    NEAR
  575.  
  576. ;   Get the current value of control interrupt vector to make sure something 
  577. ;   else doesn't use it already.
  578.  
  579.         MOV  AL,CONTROL_INTERRUPT   ; interrupt number in AL
  580.         DOS  GET_INT_VECTOR         ; dos function call to get interrupt vector
  581.         OR   BX,BX                  ; is bx 0?
  582.         JNE  ERROR_EXIT             ; if not, don't install anything
  583.         MOV  BX,ES                  ; bx = es
  584.         OR   BX,BX                  ; is es 0?
  585.         JNE  ERROR_EXIT             ; if not, don't install anything
  586.  
  587. ;   Set control interrupt vector to the address of CONTROL_ISR.
  588.  
  589.         MOV  BX,CS
  590.         MOV  DS,BX                  ; ds = cs
  591.         MOV  DX,OFFSET CONTROL_ISR  ; move offset of new routine into dx
  592.         MOV  AL,CONTROL_INTERRUPT   ; interrupt number in al
  593.         DOS  SET_INT_VECTOR         ; dos function call to set interrupt vector
  594.  
  595.         RET
  596.  
  597. ;    This branch is taken if there is already something in the control 
  598. ;    interrupt vector.
  599.  
  600. ERROR_EXIT:
  601.  
  602.         MOV  DX,OFFSET ERROR_MESSAGE
  603.         DOS  DISPLAY_STRING         ; Display the error message on the screen
  604.         INT  TERMINATE              ; Terminate without staying resident
  605.  
  606. INSTALL_CONTROL_INTERRUPT   ENDP
  607.  
  608.  
  609. ;-----------------------------------------------------------------------;
  610. ;   This routine changes the interrupt vector for interrupt 1C.  The    ;
  611. ;   old interrupt vector is saved for future use, and the address of    ;
  612. ;   the NEW_TIMER routine replaces it in the interrupt vector table.    ;
  613. ;-----------------------------------------------------------------------;
  614.  
  615.  
  616. REPLACE_TIMER PROC NEAR
  617.  
  618. ;   Get the existing timer interrupt vector.
  619.  
  620.         MOV  AL,TIMER_INTERRUPT     ; interrupt number in AL
  621.         DOS  GET_INT_VECTOR         ; dos function call to get interrupt vector
  622.         MOV  CS:OLD_OFS,BX          ; save old offset
  623.         MOV  CS:OLD_SEG,ES          ; and segment
  624.  
  625. ;   Now overwrite the old interrupt vector with a new one.
  626.  
  627.         MOV  BX,CS
  628.         MOV  DS,BX                  ; ds = cs
  629.         MOV  DX,OFFSET NEW_TIMER    ; move offset of new routine into dx
  630.         MOV  AL,TIMER_INTERRUPT     ; interrupt number
  631.         DOS  SET_INT_VECTOR         ; dos function call to set interrupt vector
  632.  
  633.         RET
  634. REPLACE_TIMER   ENDP
  635.  
  636.  
  637. ;-----------------------------------------------------------------------------;
  638. ;                                                                             ;
  639. ;   This routine replaces several interrupt vectors with the addresses of     ;
  640. ;   SYS_PROF's piggyback ISRs.  The interrupts whose ISR's are to be          ;
  641. ;   replaced are found in the INT_NUMS array; the addresses of the piggyback  ;
  642. ;   ISRs are found in the NEW_ISR_ADDRESS array; and the old interrupt vectors;
  643. ;   are stored in the OLD_INTERRUPT_VECTORS array.                            ;
  644. ;                                                                             ;
  645. ;   If a particular entry in the INT_NUMS table is zero, the replacement of   ;
  646. ;   that interrupt vector is skipped.                                         ;
  647. ;                                                                             ;
  648. ;-----------------------------------------------------------------------------;
  649.  
  650. REPLACE_SYSTEM_INTERRUPTS  PROC    NEAR
  651.  
  652. ;   Initialize registers.  CX will contain the number of interrupts to be 
  653. ;   intercepted, SI will point to the table which will contain the old 
  654. ;   interrupt vectors, and DI will contain the offset into the tables.
  655.  
  656.         MOV  CX,NUMBER_OF_INTERRUPTS
  657.         MOV  SI,OFFSET OLD_INTERRUPT_VECTORS
  658.         MOV  DI,0
  659.  
  660. ;   This loop will be repeated for each interrupt that is to be intercepted.
  661.  
  662. REPLACE_INTERRUPT_LOOP:
  663.  
  664.         PUSH DI                         ; Save DI
  665.  
  666. ;   If the interrupt number in the INT_NUMS table is zero, this one should be 
  667. ;   skipped.
  668.  
  669.         CMP  INT_NUMS[DI],0
  670.         JE   END_OF_LOOP
  671.  
  672. ;   The routine REPLACE_INTERRUPT_VECTOR expects three parameters: the address
  673. ;   of the new ISR, the interrupt number, and the storage location for the 
  674. ;   original interrupt vector.  They are pushed onto the stack in reverse order.
  675.  
  676.         PUSH SI                         ; Push offset into old-vector table
  677.         MOV  AL,INT_NUMS[DI]
  678.         XOR  AH,AH
  679.         PUSH AX                         ; Push interrupt number
  680.         SHL  DI,1
  681.         PUSH NEW_ISR_ADDRESS[DI]        ; Push table index
  682.         CALL REPLACE_INTERRUPT_VECTOR   ; Replace the interrupt vector
  683.         ADD  SP,4                       ; Clean up the stack and restore
  684.         POP  SI                         ;   SI in the process
  685.  
  686. ;   This section increments the pointers before the next iteration.
  687.  
  688. END_OF_LOOP:
  689.         POP  DI
  690.         INC  DI
  691.         ADD  SI,4
  692.         LOOP REPLACE_INTERRUPT_LOOP
  693.  
  694. ;   Return to calling routine.
  695.  
  696.         RET
  697.  
  698. REPLACE_SYSTEM_INTERRUPTS  ENDP
  699.  
  700.  
  701.  
  702. ;-----------------------------------------------------------------------------;
  703. ;                                                                             ;
  704. ;   This routine will replace a single interrupt vector.  The location of the ;
  705. ;   new ISR, the interrupt number, and a location at which to store the old   ;
  706. ;   interrupt vector are passed in on the stack.                              ;
  707. ;                                                                             ;
  708. ;-----------------------------------------------------------------------------;
  709.  
  710. REPLACE_INTERRUPT_VECTOR    PROC    NEAR
  711.  
  712.         PUSH BP
  713.         MOV  BP,SP                  ; Establish local stack frame
  714.  
  715. ;   Save the old interrupt vector
  716.  
  717.         MOV  AX,[BP+6]              ; Interrupt number into AL
  718.         DOS  GET_INT_VECTOR         ; Use DOS call to get interrupt vector
  719.         MOV  DI,[BP+8]              ; Move the safe storage address into DI
  720.         MOV  CS:[DI],BX             ; Save the offset
  721.         MOV  CS:[DI+2],ES           ; Save the segment
  722.  
  723. ;   Now replace the interrupt vector
  724.  
  725.         MOV  DX,CS
  726.         MOV  DS,DX                  ; ds = cs
  727.         MOV  DX,[BP+4]              ; Move offset into DX
  728.         MOV  AX,[BP+6]              ; Interrupt number into AL
  729.         DOS  SET_INT_VECTOR         ; Use DOS call to set interrupt vector
  730.  
  731. ;   Restore old stack frame and return
  732.  
  733.         MOV  SP,BP
  734.         POP  BP
  735.         RET
  736.  
  737. REPLACE_INTERRUPT_VECTOR    ENDP
  738.  
  739. ;-----------------------------------------------------------------------------;
  740. ;   This data is necessary only for initialization, and does not need to      ;
  741. ;   remain resident.                                                          ;
  742. ;-----------------------------------------------------------------------------;
  743.  
  744. COPYRIGHT_NOTICE    DB  10,13,10,13
  745.                     DB  '(C) Copyright 1988 G. Kent Cobb - All Rights Reserved$'
  746. ERROR_MESSAGE       DB  10,13,10,13,'Cannot install profiler.  Terminating.$'
  747.  
  748. INT_NUMS    DB PRINT_SCREEN_INTERRUPT      
  749.             DB VIDEO_INTERRUPT
  750.             DB DISK_INTERRUPT
  751.             DB COMM_INTERRUPT              
  752.             DB KEYBOARD_INTERRUPT
  753.             DB PRINTER_INTERRUPT           
  754.             DB DOS_FUNC_INTERRUPT
  755.             DB ABS_DISK_READ_INTERRUPT     
  756.             DB ABS_DISK_WRITE_INTERRUPT    
  757.  
  758. NEW_ISR_ADDRESS LABEL   WORD
  759.         DW OFFSET INTERRUPT_HANDLER1
  760.         DW OFFSET INTERRUPT_HANDLER2
  761.         DW OFFSET INTERRUPT_HANDLER3
  762.         DW OFFSET INTERRUPT_HANDLER4
  763.         DW OFFSET INTERRUPT_HANDLER5
  764.         DW OFFSET INTERRUPT_HANDLER6
  765.         DW OFFSET INTERRUPT_HANDLER7
  766.         DW OFFSET INTERRUPT_HANDLER8
  767.         DW OFFSET INTERRUPT_HANDLER9
  768.  
  769. ;----------------------------------------------------------------------------;
  770. ;                This stack is used during initialization only.              ;
  771. ;----------------------------------------------------------------------------;
  772.  
  773. OUR_STACK   DD 100H DUP (0)
  774. END_STACK   EQU $           ; SP is initialized to this value
  775.  
  776. CODE_SEG    ENDS
  777.  
  778.             END JUMP_TO_INIT
  779.  
  780.