home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
sysutl
/
sysprof3.arc
/
ORIGINAL.ARC
/
SYS_PROF.ASM
< prev
Wrap
Assembly Source File
|
1988-06-16
|
30KB
|
780 lines
;-----------------------------------------------------------------------------;
; ;
; Listing 1 ;
; ;
; NAME : SYS_PROF ;
; ;
; DATE : March 24, 1988 ;
; ;
; AUTHOR : (C) Copyright 1988 G. Kent Cobb - All Rights Reserved ;
; ;
; DESCRIPTION : ;
; This is the terminate-and-stay-resident portion of a system profiler. ;
; It installs several interrupt handlers, which monitor the occurrences ;
; and duration of a number of software interrupts. ;
; ;
;-----------------------------------------------------------------------------;
;----------------------------------------------------------------------------;
; Interrupt numbers ;
;----------------------------------------------------------------------------;
TIMER_INTERRUPT EQU 1CH
TERMINATE EQU 20H
TERM_AND_STAY_RES EQU 27H
CONTROL_INTERRUPT EQU 60H
;----------------------------------------------------------------------------;
; MS-DOS functions (Interrupt 21H services) ;
;----------------------------------------------------------------------------;
DOS MACRO OP
MOV AH,DOS_&OP
INT 21H
ENDM
DOS_DISPLAY_STRING EQU 09H
DOS_SET_INT_VECTOR EQU 25H
DOS_GET_INT_VECTOR EQU 35H
;----------------------------------------------------------------------------;
; This is a list of all the interrupts that are intercepted by SYS_PROF. ;
;----------------------------------------------------------------------------;
NUMBER_OF_INTERRUPTS EQU 9
PRINT_SCREEN_INTERRUPT EQU 5H
VIDEO_INTERRUPT EQU 10H
DISK_INTERRUPT EQU 13H
COMM_INTERRUPT EQU 14H
KEYBOARD_INTERRUPT EQU 16H
PRINTER_INTERRUPT EQU 17H
DOS_FUNC_INTERRUPT EQU 21H
ABS_DISK_READ_INTERRUPT EQU 25H
ABS_DISK_WRITE_INTERRUPT EQU 26H
;----------------------------------------------------------------------------;
; These are the number of distinct services defined for each interrupt. ;
; The OCCURRENCES array contains two double words for each service, and ;
; two additional double words for each interrupt. If an interrupt is ;
; generated with a service number that is out of range, the data for it ;
; will accumulate in this additional bin. ;
;----------------------------------------------------------------------------;
PRINT_SCREEN_SERVICES EQU 0
VIDEO_SERVICES EQU 20
DISK_SERVICES EQU 24
COMM_SERVICES EQU 4
KEYBOARD_SERVICES EQU 3
PRINTER_SERVICES EQU 3
DOS_FUNC_SERVICES EQU 99
ABS_DISK_READ_SERVICES EQU 0
ABS_DISK_WRITE_SERVICES EQU 0
;-----------------------------------------------------------------------;
; This macro defines the handling of the intercepted interrupts. The ;
; INT_NUM parameter that the macro expects is an index into the ;
; MAX_SERVICES and OFFSETS tables. ;
; ;
; Interrupts 25H and 26H are handled in a manner which is very ;
; similar, but slightly different from the other interrupts. If this ;
; macro is invoked with a second parameter, code is included to ;
; provide the special handling that these interrupts require. ;
;-----------------------------------------------------------------------;
PERFORM_INTERRUPT MACRO INT_NUM,SPECIAL
INTERRUPT_HANDLER&INT_NUM PROC FAR
; Turn interrupts back on.
STI
; Save the existing interrupt and service numbers on the stack.
PUSH CS:WORD PTR INTERRUPT
; Push the flags onto the stack now (before we execute any instructions which
; might change them) in order to simulate an interrupt later.
PUSHF
; Save the value of WATCH on the stack while we're changing INTERRUPT and
; SERVICE.
PUSH CS:WATCH
; Turn accumulation off, set new INTERRUPT and SERVICE values, make sure
; the service number is valid, and then restore accumulation to its previous
; state.
MOV CS:WATCH,0
MOV CS:INTERRUPT,&INT_NUM
MOV CS:SERVICE,AH
CALL VALIDATE_SERVICE
POP CS:WATCH
; If accumulation is turned off, go straight to the real ISR.
CMP CS:WATCH,0
JE READY_FOR_INTERRUPT&INT_NUM
; If accumulation is turned on, push a one onto the stack to tell the
; ACCUMULATE routine which bin to increment, and then call it.
PUSH CS:ONE
CALL ACCUMULATE
READY_FOR_INTERRUPT&INT_NUM:
; After tabulating occurrence data, execute the real ISR
CALL CS:DWORD PTR OLD_INTERRUPT_VECTORS [ 4*(&INT_NUM-1) ]
; Interrupts 25H and 26H require special handling. Since they leave the
; flags on the stack when they return control to the calling program, we
; have an extra word on the stack which must be popped.
IFNB <SPECIAL>
POP CS:EXTRA_FLAGS
ENDIF
; On return, pop the interrupt and service numbers that were current before
; this one.
POP CS:WORD PTR INTERRUPT
; For most interrupts, return with RET 2 rather than IRET. This will
; preserve whatever treatment the real ISR uses for the flags.
IFB <SPECIAL>
RET 2
; Interrupts 25H and 26H are special cases. The calling program expects the
; flags to still be on the stack, so we use RET instead.
ELSE
RET
ENDIF
INTERRUPT_HANDLER&INT_NUM ENDP
ENDM
CODE_SEG SEGMENT PUBLIC
ASSUME CS:CODE_SEG , DS:CODE_SEG
;-----------------------------------------------------------------------;
; This is the entry point for the program. Control is immediately ;
; transferred to the initialization code, which is located in the ;
; portion of the program which does not remain resident. ;
;-----------------------------------------------------------------------;
ORG 100H ; COM FILE
JUMP_TO_INIT PROC FAR
JMP INIT
JUMP_TO_INIT ENDP
;-----------------------------------------------------------------------------;
; The handling for all nine intercepted interrupts is very similar, and is ;
; defined by the PERFORM_INTERRUPT macro. This section contains the macro ;
; calls. ;
;-----------------------------------------------------------------------------;
; Print screen interrupt
PERFORM_INTERRUPT 1
; BIOS Video interrupt
PERFORM_INTERRUPT 2
; BIOS Disk interrupt
PERFORM_INTERRUPT 3
; BIOS Comm interrupt
PERFORM_INTERRUPT 4
; BIOS Keyboard interrupt (16H)
PERFORM_INTERRUPT 5
; BIOS Printer interrupt
PERFORM_INTERRUPT 6
; DOS Function calls interrupt
PERFORM_INTERRUPT 7
; The last two interrupts, 25H and 26H, require special handling since the
; real ISRs do not pop the flags from the stack upon completion. By passing
; a second parameter to the PERFORM_INTERRUPT macro, the code to handle this
; will be included by the preprocessor when the macro is expanded.
; DOS Absolute disk read interrupt
PERFORM_INTERRUPT 8 SPECIAL
; DOS Absolute disk write interrupt
PERFORM_INTERRUPT 9 SPECIAL
;-----------------------------------------------------------------------;
; This routine is a piggyback ISR for interrupt 1C. It tabulates ;
; the current interrupt and service numbers if WATCH is non-zero, ;
; and then executes the real ISR. ;
;-----------------------------------------------------------------------;
NEW_TIMER PROC NEAR
STI
CMP CS:WATCH,0 ; check to see if we accumulate
JE DO_OLD_INT1C ; skip accumulate if 0
PUSH CS:ZERO ; Push parameter onto stack
CALL ACCUMULATE ; if not 0, accumulate data
DO_OLD_INT1C:
JMP CS:DWORD PTR OLD_INT1C ; jump to old interrupt 1C
NEW_TIMER ENDP
;-----------------------------------------------------------------------;
; This routine validates the service number that is stored in the ;
; memory location SERVICE. For each interrupt, there is a maximum ;
; service number which is meaningful. This routine obtains that ;
; number from the MAX_SERVICES array, and compares it to the value of ;
; SERVICE. If SERVICE is not between zero and MAX - 1, inclusive, it ;
; is reset to MAX. All services which are requested with invalid or ;
; unknown service numbers will then accumulate in an "Other" bin. ;
;-----------------------------------------------------------------------;
VALIDATE_SERVICE PROC NEAR
PUSH BX ; Save BX register
MOV BL,CS:INTERRUPT ; Retrieve the interrupt number
XOR BH,BH
DEC BX ; Adjust indexing to zero-based
MOV BL,CS:MAX_SERVICE[BX]
; Get the maximum service number for this int
CMP BL,CS:SERVICE ; Compare to current service number
JG SERVICE_VALID ; If BL is greater, everything is OK
MOV CS:SERVICE,BL ; Otherwise, set the service to the maximum #
SERVICE_VALID:
POP BX ; Restore BX register and return
RET
VALIDATE_SERVICE ENDP
;-----------------------------------------------------------------------;
; This routine increments a counter in the data table. It uses the ;
; current interrupt and service numbers to determine the proper loca- ;
; tion within the table. Either of two counters may be incremented, ;
; depending on the value of the parameter passed in on the stack. If ;
; the routine is called from the timer tick ISR, the parameter will ;
; be zero, and the first of the two will be incremented. If it is ;
; called from one of the software ISRs, the parameter will be one, ;
; and the second will be incremented instead. ;
;-----------------------------------------------------------------------;
ACCUMULATE PROC NEAR
PUSH BP
MOV BP,SP ; Establish local stack frame
PUSH AX
PUSH BX ; push registers
; Calculate offset into the table of occurrences.
MOV BL,CS:INTERRUPT ; move code for interrupt currently being
; serviced into bl
XOR BH,BH ; zero out bh
SHL BX,1 ; Multiply by two since OFFSETS are words.
MOV BX,CS:OFFSETS[BX] ; Get the offset into the accumulation table
MOV AL,CS:SERVICE ; move code for service currently being
; performed into al
XOR AH,AH ; zero out ah
SHL AX,1 ; multiply by 4 to convert number of
SHL AX,1 ; double words to number of bytes
SHL AX,1 ; multiply by 2 since there are two double
; words for each service
ADD BX,AX ; add offset to get offset of data for this
; service
CMP WORD PTR [BP+4],0 ; Is the parameter zero?
JE INC_DOUBLE ; If yes, increment the first double word
ADD BX,4 ; But if not, increment the second
INC_DOUBLE:
INC CS:WORD PTR [BX] ; Increment low-order word
JNZ NO_CARRY
ADD BX,2 ; If counter rolls over, increment high-
INC CS:WORD PTR [BX] ; order word also
NO_CARRY:
POP BX ; Restore registers
POP AX
POP BP ; Restore old stack frame
RET 2
ACCUMULATE ENDP
;-----------------------------------------------------------------------;
; This is the service routine for the SYS_PROF control interrupt. It ;
; provides the following services: ;
; ;
; AH=0 : Report on/off status in AX ;
; AH=1 : Turn accumulation off ;
; AH=2 : Turn accumulation on ;
; AH=3 : Return address of data table in ES:BX ;
; AH=4 : Reset data table to zeroes ;
; ;
; These services are used by the PROFCTRL program to control the ;
; operations of SYS_PROF. ;
;-----------------------------------------------------------------------;
CONTROL_ISR PROC NEAR
STI ; Enable interrupts
PUSH CX ; Save registers
PUSH DI
CMP AH,0 ; Is AH equal to 0?
JG AH_NOT_0 ; No, skip to next test
; If we get to this point, AH is zero, which indicates that we should
; report the status of the accumulation flag.
MOV AX,CS:WATCH
JMP CONTROL_COMPLETE
AH_NOT_0:
CMP AH,1 ; Is AH equal to 1?
JG AH_NOT_1 ; No, skip to next test
; If we get to this point, AH is one, which indicates that accumulation
; is to be turned off.
MOV CS:WATCH,0 ; Turn off accumulation
JMP OK
AH_NOT_1:
CMP AH,2 ; Is AH equal to 2?
JG AH_NOT_2 ; No, skip to next test
; If we get to this point, AH is two, which indicates that accumulation
; is to be turned on.
MOV CS:WATCH,1 ; Turn accumulation on
JMP OK
AH_NOT_2:
CMP AH,3 ; Is AH equal to 3?
JG AH_NOT_3 ; No, skip to next test
; If we get to this point, AH is three, which indicates that the segmented
; address of the data accumulation table should be returned in ES:BX.
MOV BX,CS
MOV ES,BX ; es = cs
MOV BX,OFFSET OCCURRENCES
; offset of data table
JMP OK
AH_NOT_3:
CMP AH,4 ; Is AH equal to 4?
JG BAD_VALUE ; No, it must be invalid.
; If we get to this point, AH is four, which indicates that the data table
; should be reset to zeroes.
PUSH ES ; Save current value of ES
MOV CS:WATCH,0 ; Don't want to accumulate while we're re-initializing
MOV AX,CS
MOV ES,AX ; Make es = cs in order to use STOSW instruction
MOV DI,OFFSET OCCURRENCES
; DI is set to start of data table for same reason
MOV CX,OFFSET END_OF_TABLE
SUB CX,DI
SHR CX,1 ; CX contains number of words to zero
CLD
XOR AX,AX
REP STOSW ; Zero the data table
POP ES ; Restore ES
JMP OK
BAD_VALUE:
MOV AH,0FFH ; Set AH to -1 to indicate error
JMP CONTROL_COMPLETE
OK:
XOR AH,AH ; Set AH to 0 to indicate success
CONTROL_COMPLETE:
POP DI ; Restore registers
POP CX
IRET
CONTROL_ISR ENDP
;-----------------------------------------------------------------------;
; DATA AREA ;
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; This variable controls data accumulation. Service requests and ;
; timer ticks are tabulated if it is non-zero. ;
;-----------------------------------------------------------------------;
WATCH DW 0
;-----------------------------------------------------------------------;
; The indices of the interrupt and service currently being performed ;
; are stored in this location. ;
;-----------------------------------------------------------------------;
INTERRUPT DB 0
SERVICE DB 0
;-----------------------------------------------------------------------;
; This array is used to store the segmented addresses of all the real ;
; interrupt service routines. It is initialized by ;
; REPLACE_SYSTEM_INTERRUPTS, and is used in the PERFORM_INTERRUPT ;
; macro. ;
;-----------------------------------------------------------------------;
OLD_INTERRUPT_VECTORS DD 10 DUP(0)
;-----------------------------------------------------------------------;
; This table has one entry for each interrupt that is intercepted by ;
; SYS_PROF. The entry for a particular interrupt contains the number ;
; of distinct services that can be requested in AH. The values in the;
; table are checked by the VALIDATE_SERVICE routine to prevent ;
; corruption of the data tabulation process. ;
;-----------------------------------------------------------------------;
MAX_SERVICE DB PRINT_SCREEN_SERVICES
DB VIDEO_SERVICES
DB DISK_SERVICES
DB COMM_SERVICES
DB KEYBOARD_SERVICES
DB PRINTER_SERVICES
DB DOS_FUNC_SERVICES
DB ABS_DISK_READ_SERVICES
DB ABS_DISK_WRITE_SERVICES
;-----------------------------------------------------------------------;
; This area is used to tabulate the number of request for each ;
; service, and the timer ticks that occur during each service. ;
;-----------------------------------------------------------------------;
OCCURRENCES LABEL DWORD
OTHER_BIN DD 2 DUP (0)
PRINT_SCREEN_BIN DD 2*(1+PRINT_SCREEN_SERVICES) DUP (0)
VIDEO_BIN DD 2*(1+VIDEO_SERVICES) DUP (0)
DISK_BIN DD 2*(1+DISK_SERVICES) DUP (0)
COMM_BIN DD 2*(1+COMM_SERVICES) DUP (0)
KEYBOARD_BIN DD 2*(1+KEYBOARD_SERVICES) DUP (0)
PRINTER_BIN DD 2*(1+PRINTER_SERVICES) DUP (0)
DOS_FUNC_BIN DD 2*(1+DOS_FUNC_SERVICES) DUP (0)
ABS_DISK_READ_BIN DD 2*(1+ABS_DISK_READ_SERVICES) DUP (0)
ABS_DISK_WRITE_BIN DD 2*(1+ABS_DISK_WRITE_SERVICES) DUP (0)
END_OF_TABLE LABEL DWORD
;-----------------------------------------------------------------------;
; This is a table of offsets into the previous table. It defines the ;
; offset of the start of the data area for each interrupt. ;
;-----------------------------------------------------------------------;
OFFSETS LABEL WORD
DW OTHER_BIN
DW PRINT_SCREEN_BIN
DW VIDEO_BIN
DW DISK_BIN
DW COMM_BIN
DW KEYBOARD_BIN
DW PRINTER_BIN
DW DOS_FUNC_BIN
DW ABS_DISK_READ_BIN
DW ABS_DISK_WRITE_BIN
OLD_INT1C EQU $ ; address of old timer interrupt
OLD_OFS DW ? ; offset of old timer interrupt
OLD_SEG DW ? ; segment of old timer interrupt
ZERO DW 0
ONE DW 1
EXTRA_FLAGS DW 0
;-----------------------------------------------------------------------;
; This is the main routine of the initialization section. It replaces;
; several interrupt vectors, and then terminates, leaving the data ;
; tables and the interrupt service routines resident. ;
;-----------------------------------------------------------------------;
INIT PROC NEAR
; Use internal stack during initialization
MOV SP,OFFSET END_STACK
; Display copyright notice
MOV DX,OFFSET COPYRIGHT_NOTICE
DOS DISPLAY_STRING
; Install interrupt handlers.
CALL INSTALL_CONTROL_INTERRUPT
CALL REPLACE_TIMER
CALL REPLACE_SYSTEM_INTERRUPTS
; Terminate and stay resident
MOV AX,CS
MOV DS,AX
MOV DX,OFFSET INIT + 100H
INT TERM_AND_STAY_RES
INIT ENDP
;-----------------------------------------------------------------------;
; This routine initializes the interrupt vector for the SYS_PROF ;
; control interrupt. If it has been initialized previously (as ;
; indicated by a non-zero value), SYS_PROF will terminate without ;
; remaining resident. This makes it possible to run SYS_PROF several ;
; times in succession without taking up additional memory each time, ;
; and without checking beforehand to see if it is already resident. ;
;-----------------------------------------------------------------------;
INSTALL_CONTROL_INTERRUPT PROC NEAR
; Get the current value of control interrupt vector to make sure something
; else doesn't use it already.
MOV AL,CONTROL_INTERRUPT ; interrupt number in AL
DOS GET_INT_VECTOR ; dos function call to get interrupt vector
OR BX,BX ; is bx 0?
JNE ERROR_EXIT ; if not, don't install anything
MOV BX,ES ; bx = es
OR BX,BX ; is es 0?
JNE ERROR_EXIT ; if not, don't install anything
; Set control interrupt vector to the address of CONTROL_ISR.
MOV BX,CS
MOV DS,BX ; ds = cs
MOV DX,OFFSET CONTROL_ISR ; move offset of new routine into dx
MOV AL,CONTROL_INTERRUPT ; interrupt number in al
DOS SET_INT_VECTOR ; dos function call to set interrupt vector
RET
; This branch is taken if there is already something in the control
; interrupt vector.
ERROR_EXIT:
MOV DX,OFFSET ERROR_MESSAGE
DOS DISPLAY_STRING ; Display the error message on the screen
INT TERMINATE ; Terminate without staying resident
INSTALL_CONTROL_INTERRUPT ENDP
;-----------------------------------------------------------------------;
; This routine changes the interrupt vector for interrupt 1C. The ;
; old interrupt vector is saved for future use, and the address of ;
; the NEW_TIMER routine replaces it in the interrupt vector table. ;
;-----------------------------------------------------------------------;
REPLACE_TIMER PROC NEAR
; Get the existing timer interrupt vector.
MOV AL,TIMER_INTERRUPT ; interrupt number in AL
DOS GET_INT_VECTOR ; dos function call to get interrupt vector
MOV CS:OLD_OFS,BX ; save old offset
MOV CS:OLD_SEG,ES ; and segment
; Now overwrite the old interrupt vector with a new one.
MOV BX,CS
MOV DS,BX ; ds = cs
MOV DX,OFFSET NEW_TIMER ; move offset of new routine into dx
MOV AL,TIMER_INTERRUPT ; interrupt number
DOS SET_INT_VECTOR ; dos function call to set interrupt vector
RET
REPLACE_TIMER ENDP
;-----------------------------------------------------------------------------;
; ;
; This routine replaces several interrupt vectors with the addresses of ;
; SYS_PROF's piggyback ISRs. The interrupts whose ISR's are to be ;
; replaced are found in the INT_NUMS array; the addresses of the piggyback ;
; ISRs are found in the NEW_ISR_ADDRESS array; and the old interrupt vectors;
; are stored in the OLD_INTERRUPT_VECTORS array. ;
; ;
; If a particular entry in the INT_NUMS table is zero, the replacement of ;
; that interrupt vector is skipped. ;
; ;
;-----------------------------------------------------------------------------;
REPLACE_SYSTEM_INTERRUPTS PROC NEAR
; Initialize registers. CX will contain the number of interrupts to be
; intercepted, SI will point to the table which will contain the old
; interrupt vectors, and DI will contain the offset into the tables.
MOV CX,NUMBER_OF_INTERRUPTS
MOV SI,OFFSET OLD_INTERRUPT_VECTORS
MOV DI,0
; This loop will be repeated for each interrupt that is to be intercepted.
REPLACE_INTERRUPT_LOOP:
PUSH DI ; Save DI
; If the interrupt number in the INT_NUMS table is zero, this one should be
; skipped.
CMP INT_NUMS[DI],0
JE END_OF_LOOP
; The routine REPLACE_INTERRUPT_VECTOR expects three parameters: the address
; of the new ISR, the interrupt number, and the storage location for the
; original interrupt vector. They are pushed onto the stack in reverse order.
PUSH SI ; Push offset into old-vector table
MOV AL,INT_NUMS[DI]
XOR AH,AH
PUSH AX ; Push interrupt number
SHL DI,1
PUSH NEW_ISR_ADDRESS[DI] ; Push table index
CALL REPLACE_INTERRUPT_VECTOR ; Replace the interrupt vector
ADD SP,4 ; Clean up the stack and restore
POP SI ; SI in the process
; This section increments the pointers before the next iteration.
END_OF_LOOP:
POP DI
INC DI
ADD SI,4
LOOP REPLACE_INTERRUPT_LOOP
; Return to calling routine.
RET
REPLACE_SYSTEM_INTERRUPTS ENDP
;-----------------------------------------------------------------------------;
; ;
; This routine will replace a single interrupt vector. The location of the ;
; new ISR, the interrupt number, and a location at which to store the old ;
; interrupt vector are passed in on the stack. ;
; ;
;-----------------------------------------------------------------------------;
REPLACE_INTERRUPT_VECTOR PROC NEAR
PUSH BP
MOV BP,SP ; Establish local stack frame
; Save the old interrupt vector
MOV AX,[BP+6] ; Interrupt number into AL
DOS GET_INT_VECTOR ; Use DOS call to get interrupt vector
MOV DI,[BP+8] ; Move the safe storage address into DI
MOV CS:[DI],BX ; Save the offset
MOV CS:[DI+2],ES ; Save the segment
; Now replace the interrupt vector
MOV DX,CS
MOV DS,DX ; ds = cs
MOV DX,[BP+4] ; Move offset into DX
MOV AX,[BP+6] ; Interrupt number into AL
DOS SET_INT_VECTOR ; Use DOS call to set interrupt vector
; Restore old stack frame and return
MOV SP,BP
POP BP
RET
REPLACE_INTERRUPT_VECTOR ENDP
;-----------------------------------------------------------------------------;
; This data is necessary only for initialization, and does not need to ;
; remain resident. ;
;-----------------------------------------------------------------------------;
COPYRIGHT_NOTICE DB 10,13,10,13
DB '(C) Copyright 1988 G. Kent Cobb - All Rights Reserved$'
ERROR_MESSAGE DB 10,13,10,13,'Cannot install profiler. Terminating.$'
INT_NUMS DB PRINT_SCREEN_INTERRUPT
DB VIDEO_INTERRUPT
DB DISK_INTERRUPT
DB COMM_INTERRUPT
DB KEYBOARD_INTERRUPT
DB PRINTER_INTERRUPT
DB DOS_FUNC_INTERRUPT
DB ABS_DISK_READ_INTERRUPT
DB ABS_DISK_WRITE_INTERRUPT
NEW_ISR_ADDRESS LABEL WORD
DW OFFSET INTERRUPT_HANDLER1
DW OFFSET INTERRUPT_HANDLER2
DW OFFSET INTERRUPT_HANDLER3
DW OFFSET INTERRUPT_HANDLER4
DW OFFSET INTERRUPT_HANDLER5
DW OFFSET INTERRUPT_HANDLER6
DW OFFSET INTERRUPT_HANDLER7
DW OFFSET INTERRUPT_HANDLER8
DW OFFSET INTERRUPT_HANDLER9
;----------------------------------------------------------------------------;
; This stack is used during initialization only. ;
;----------------------------------------------------------------------------;
OUR_STACK DD 100H DUP (0)
END_STACK EQU $ ; SP is initialized to this value
CODE_SEG ENDS
END JUMP_TO_INIT