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