📄 int_pkg.asm
字号:
INCLUDE TITLE.MAC
.TITLE <INT_PKG -- Interrupt Vector Interface Routines>
.SBTTL History
; int_pkg.asm 17 Nov 83 Craig Milo Rogers at USC/ISI
; Debugged in non-DOS, DOS 1, and DOS 2 configurations.
; Set to non-DOS for actual use.
; Added int_prev().
; int_pkg.asm 15 Nov 83 Craig Milo Rogers at USC/ISI
; Created this package to change and restore interrupt vectors
; on the IBM PC.
.SBHED Overview
; This package manages interrupt vectors on the IBM PC.
;
; 1) The package may be compiled to use the DOS calls to get and
; set interrupt vectors, or it may be compiled to do these
; tasks directly.
;
; 2) The basic services that this module provides to clients are
; to set and restore interrupt vectors. When an interrupt vector
; is set, its old contents are saved. The old contents may be
; restored upon demand by a client, or when a package termination
; (clean-up) call is issued.
;
; 3) Nested calls to set and restore the same interrupt vector are
; not supported.
;
; 4) The old interrupt vectors are saved in a local storage area.
; The length of the storage area is an assembly parameter. A
; fixed area was selected over a linked list because a linked
; list is more likely to be damaged by a runaway program.
; Entry points (Lattice C 1.05 calling conventions):
; void
; int_ini() /* Initializes the saved interrupt database.*/
; bool /* FALSE ==> vector in use or out of mem. */
; int_setup(vec, newip, newcs) /* Setup an interrupt vector. */
; int vec; /* Interrupt vector number. */
; int newip; /* Instruction pointer for interrupt code. */
; int newcs; /* Code segment for interrupt code. */
; /* Together, newip and newcs are the same
; * as a Large model pointer-to-function.
; * However, C routines may not be directly
; * called this way, since lots of registers
; * must be saved and setup first before C
; * code can be used. */
; long /* Actually, a pointer to a "function". */
; /* 0L ==> vector not saved, or was empty. */
; int_prev(vec) /* Returns prev. contents of the vector. */
; int vec; /* Interrupt vector number. */
; bool /* FALSE ==> vector not in use. */
; int_restore(vec) /* Restore an interrupt vector. */
; int vec; /* Interrupt vector number. */
; void
; int_trm() /* Terminate, ie restore all vectors. */
.SBHED Declarations
IF1
INCLUDE DOS.MAC ; C segments.
INCLUDE BMAC.MAC ; C calling conventions.
ENDIF
; Here are the two configuration parameters. Ideally these
; should come from an include file, not the source file.
NODOS EQU 0 ; 0 ==> Use DOS calls, 1 ==> Avoid DOS.
NSAVVEC EQU 10 ; Nomber of vectors to handle.
; The following structure saves old interrupt vector contents:
SVEC STRUC ; Saves old vectors.
SAVVEC DW ? ; Saved vector number.
SAVIP DW ? ; Saved Instruction Pointer.
SAVCS DW ? ; Saved Code Segment.
SVEC ENDS
NOVEC EQU 0FFFFH ; Indicates an unused entry.
; Return Codes:
TRUE EQU 1 ; Truth.
FALSE EQU 0 ; Falsehood.
.SBHED <Data Storage>
ABS0 SEGMENT AT 0H ; Segment with interrupt vectors.
ABS0 ENDS
DSEG
SAVAREA SVEC NSAVVEC DUP(<>) ; Saved interrupt vector blocks.
IFE NODOS ; Are we using DOS?
DOSTYPE DW ? ; Gets the DOS level.
ENDIF
ENDDS
PSEG
DB '(C) Copyright Inner Loop Software, 1983'
.SBHED <FINDVEC -- Internal Routine to Find a Vector>
; Called with the vector in AX.
; Returns with a pointer to the vector save block in SI.
; Carry clear -- found the vector save entry.
; Carry set -- didn't find the vector save entry.
; Modifies: CX, SI, CF
FINDVEC PROC NEAR ; Internal routine.
MOV SI,OFFSET SAVAREA ; Address of save area.
MOV CX,NSAVVEC ; Number of vector save entries.
FINDLOOP:
CMP [SI].SAVVEC,AX ; Is this the vector?
JE FOUNDIT ; (yup, too bad)
ADD SI,TYPE SVEC ; Advance SI to next save entry.
LOOP FINDLOOP ; Loop for number of save entries.
STC ; Set the carry flag -- not found.
RET ; Return with error set.
FOUNDIT:
CLC ; Clear carry - found entry.
RET ; Return, no error.
FINDVEC ENDP
.SBHED <INT_INI -- Initialize Saved Interrupt Database>
; void
; int_ini() /* Initializes the saved interrupt database.*/
BENTRY INT_INI
MOV SI,OFFSET SAVAREA ; Address of save area.
MOV CX,NSAVVEC ; Number of vector save entries.
XOR AX,AX ; Clear AX for a handy source of 0.
INILOOP:
MOV [SI].SAVVEC,NOVEC ; Indicate no vector present.
MOV [SI].SAVIP,AX ; Clear saved Instruction Pointer.
MOV [SI].SAVCS,AX ; Clear saved Code Segment.
ADD SI,TYPE SVEC ; Advance SI to next save entry.
LOOP INILOOP ; Loop for number of save entries.
IFE NODOS ; Are we using DOS?
MOV AH,30H ; Get DOS Version function number.
INT 21H ; DOS Function Call.
MOV DOSTYPE,AX ; Save the returned value.
ENDIF
BEND INT_INI ; That's all for initialization.
.SBHED <INT_SETUP -- Setup an Interrupt Vector>
; bool /* FALSE ==> vector in use or out of mem. */
; int_setup(vec, newip, newcs) /* Setup an interrupt vector. */
; int vec; /* Interrupt vector number. */
; int newip; /* Instruction pointer for interrupt code. */
; int newcs; /* Code segment for interrupt code. */
; /* Together, newip and newcs are the same
; * as a Large model pointer-to-function.
; * However, C routines may not be directly
; * called this way, since lots of registers
; * must be saved and setup first before C
; * code can be used. */
BENTRY INT_SETU <VEC,NEWIP,NEWCS>
MOV AX,VEC ; Vector for which we're looking.
CALL FINDVEC ; See if already allocated
JNC SETBAD ; (yup, too bad)
MOV SI,OFFSET SAVAREA ; Address of save area.
MOV CX,NSAVVEC ; Number of vector save entries.
SETFREE:
CMP [SI].SAVVEC,NOVEC ; Is this a free entry?
JE SETVEC ; (yup)
ADD SI,TYPE SVEC ; Advance SI to next save entry.
LOOP SETFREE ; Loop for number of save entries.
SETBAD:
MOV AX,FALSE ; Vector in use, or no free space.
JMP SHORT SETDONE ; Go return to the user.
SETVEC: ; Let's set the interrupt vector.
IF NODOS
; This code copies the old vector contents into the vector save
; block and sets the new vector contents, as an atomic operation. This
; eliminates the possibility of an interrupt changing the vector's
; contents while the vector is being saved.
MOV BX,ABS0 ; Get start of interrupt vectors.
MOV ES,BX ; ES is vector segment.
ASSUME ES:ABS0
; AX still has target vector.
MOV BX,AX ; Transfer vector number.
ADD BX,BX ; Convert to vector address.
ADD BX,BX
MOV CX,NEWIP ; Get the new vector offset.
MOV DX,NEWCS ; Get the new vector section.
PUSHF ; Save current interrupt setting.
CLI ; ******* Disable Interrupts *******
XCHG CX,ES:[BX] ;;; Set vector's Instruction Ptr.
XCHG DX,ES:[BX+2] ;;; Set vector's Segment Number.
MOV [SI].SAVVEC,AX ;;; Mark this save block used.
MOV [SI].SAVIP,CX ;;; Store the old vector offset.
MOV [SI].SAVCS,DX ;;; Store the old vector segment.
POPF ;;; ******* Restore Interrupts *******
;;; (Next instruction still disabled)
ASSUME ES:NOTHING
ELSE
; This code saves the old contents of the vector, then sets the new
; contents. The operations are not atomic, so there is an implicit
; assumption that the interrupt vector will not be changed (by an
; interrupt routine) which this routine is running.
CMP BYTE PTR DOSTYPE,2 ; Is this DOS 2 or greater?
JGE SETDOS2 ; (yup)
; This system is pre-DOS 2. Save the old vector without DOS.
MOV BX,ABS0 ; Get start of interrupt vectors.
MOV ES,BX ; ES is vector segment.
ASSUME ES:ABS0
; AX still has target vector.
MOV BX,AX ; Transfer vector number.
ADD BX,BX ; Convert to vector address.
ADD BX,BX
MOV CX,ES:[BX] ; Get vector's Instruction Ptr.
MOV DX,ES:[BX+2] ; Get vector's Segment Number.
MOV [SI].SAVIP,CX ; Store the old vector offset.
MOV [SI].SAVCS,DX ; Store the old vector segment.
MOV [SI].SAVVEC,AX ; Mark this save block used.
ASSUME ES:NOTHING
JMP SHORT SETDOSVEC ; Go set the vector.
SETDOS2:
; Use the DOS 2 call to get old vec. Store the vector number
; into the save block last. This interlocks the save block contents
; so it can be referenced at interrupt level.
; AX still has target vector.
MOV AH,35H ; DOS Get Vector function.
INT 21H ; DOS Function Call.
MOV [SI].SAVIP,BX ; Store the old vector offset.
PUSH ES ; Store the old vector segment
POP [SI].SAVCS ; via the stack.
MOV AX,VEC ; Get the vector number again.
MOV [SI].SAVVEC,AX ; Mark this save block used.
; Fall into SETDOSVEC...
SETDOSVEC:
; Call DOS to set the interrupt vector.
; Vector number already in AL.
MOV DX,NEWIP ; Fetch the new vector offset.
PUSH DS ; Save our data segment.
PUSH NEWCS ; Fetch the new vector segment.
POP DS ; Transfer new segment to DS.
MOV AH,25H ; DOS Set Interrupt Vector function.
INT 21H ; DOS Function Call.
POP DS ; Restore our data segment.
ENDIF
MOV AX,TRUE ; Return TRUE to caller.
; Fall into SETDONE...
SETDONE:
BEND INT_SETU
.SBHED <INT_PREV -- Return Previous Vector Contents>
; long /* Actually, a pointer to a "function". */
; /* 0L ==> vector not saved, or was empty. */
; int_prev(vec) /* Returns prev. contents of the vector. */
; int vec; /* Interrupt vector number. */
; A 0L return can meas two things: either the wrong vector was
; supplied to int_prev(), or the vector's previous contents were in fact
; zero. 0L is not a significant value for any of the vectors at the
; present time, and isn't a reasonable address for a procedure.
; However, it is quite possible for a vector to contain 0L if it has
; never been used before. So, don't treat 0L as a fatal error, but
; don't treat it as a valid procedure, either.
BENTRY INT_PREV <VEC>
MOV AX,VEC ; Vector for which we're looking.
CALL FINDVEC ; Try to find save block.
JC PREVERR ; (not found)
MOV AX,[SI].SAVCS ; AX gets segment.
MOV BX,[SI].SAVIP ; BX gets offset.
JMP SHORT PREVDONE ; Go return to the user.
PREVERR:
XOR AX,AX ; Failed to find target vector.
XOR BX,BX
PREVDONE:
BEND INT_PREV ; That's all, return code in AX, BX.
.SBHED <INT_RESTORE -- Restore a Saved Vector>
; bool /* FALSE ==> vector not in use. */
; int_restore(vec) /* Restore an interrupt vector. */
; int vec; /* Interrupt vector number. */
BENTRY INT_REST <VEC>
MOV AX,VEC ; Vector for which we're looking.
CALL FINDVEC ; Look for the saved vector.
JNC RESTVEC ; (found it)
MOV AX,FALSE ; Failed to find target vector.
JMP SHORT RESTDONE ; Go return to the user.
RESTVEC: ; SI points to the save block.
IF NODOS
MOV BX,AX ; Transfer vector number.
ADD BX,BX ; Convert to vector address.
ADD BX,BX
MOV CX,[SI].SAVIP ; Fetch the saved vector offset.
MOV DX,[SI].SAVCS ; Fetch the saved vector segment.
PUSH DS ; Save our data segment.
MOV AX,ABS0 ; Get start of interrupt vectors.
MOV DS,AX ; Now work in vector segment.
PUSHF ; Save current interrupt setting.
CLI ; ******* Disable Interrupts *******
MOV [BX],CX ;;; Restore vector's Instruction Ptr.
MOV [BX+2],DX ;;; Restore vector's Segment Number.
POPF ;;; ******* Restore Interrupts *******
POP DS ;;; Restore our data segment.
ELSE
; Use DOS call to restore the vector.
; Vector number already in AL.
MOV DX,[SI].SAVIP ; Fetch the saved vector offset.
PUSH DS ; Save our data segment.
PUSH [SI].SAVCS ; Fetch the saved vector segment.
POP DS ; Transfer saved segment to DS.
MOV AH,25H ; DOS Set Interrupt Vector function.
INT 21H ; DOS Function Call.
POP DS ; Restore our data segment.
ENDIF
MOV [SI].SAVVEC,NOVEC ; Free this saved vector block.
MOV AX,TRUE ; Return TRUE to caller.
; Fall into RESTDONE...
RESTDONE:
BEND INT_REST ; That's all, return code in AX.
.SBHED <INT_TRM -- Terminate and Restore All Vectors>
; void
; int_trm() /* Terminate, ie restore all vectors. */
BENTRY INT_TRM
MOV SI,OFFSET SAVAREA ; Address of save area.
MOV CX,NSAVVEC ; Number of vector save entries.
TRMLOOP:
CMP [SI].SAVVEC,NOVEC ; Is there a vector present?
JE TRMNEXT ; (nope)
PUSH SI ; Save SI
PUSH CX ; and CX accross subroutine call.
BCALL INT_REST <[SI].SAVVEC> ; Call the code to restore the vector.
POP CX ; Restore saved registers.
POP SI
TRMNEXT:
ADD SI,TYPE SVEC ; Advance SI to next save entry.
LOOP TRMLOOP ; Loop for number of save entries.
BEND INT_TRM ; That's all.
ENDPS
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -