📄 tsrbones.asm
字号:
; handling is underway. We do this by querying the Intel 8259A Program-
; mable Interrupt Controller (PIC) chip's In Service Register (ISR) and
; testing it to see that it is zero (i.e., nothing being serviced).
;
HotKeyPressed:
mov al,ISRREQ ;al=PIC's OCW3 to ask for ISR Register.
out PICPORT,al ;Tell PIC to get ISR ready for reading.
jmp Dally ;Give PIC time to make ISR available.
Dally: in al,PICPORT ;Fetch the ISR Register from PIC.
or al,al ;Activate processor flags.
jnz SetFlag ;If al not zero, go set flag.
;
; At this point, HotKey is known to be pressed AND NO hardware interrupt
; is being serviced. BUT is InDOS flag zero, indicating that DOS is
; not busy and therefore can safely be entered? This will now be
; checked:
;
HotKeyNoHWI:
les bx,indosptr ;es:bx = pointer to InDOS flag
mov al,es:[bx] ;al = InDOS flag.
or al,al ;Activate processor flags.
jnz SetFlag ;Jump if InDOS not zero.
;
; Include a check on Critical Error flag. Don't trigger the TSR if
; DOS is in the middle of handling a Critical Error:
;
les bx,criterrptr ;es:bx = pointer to CritErr flag.
mov al,es:[bx] ;al = CritErr flag.
;
; Also, don't trigger the TSR if time-critical Disk access is underway:
; Normally, this Disk check would not be necessary since the
; InDOS flag would not be clear during Disk accesses, BUT some
; software will bypass DOS and go directly to the BIOS Int13
; Interrupt for Disk access. Therefore, to be safe, we HAVE to
; be sure Int13 has not been entered and is not in the process
; of performing time-critical Disk stuff when we hit the TSR
; HotKey. Many TSRs don't even check this. They just depend
; upon users not to hit the HotKey during Disk access. That seems
; terribly risky to me:
;
or al,diskflag ;al = CritErr | diskflag
; (| => Logical OR).
jnz Exit09 ;If al not zero, try again later.
;
; Also, don't trigger the TSR if a PrtScrn is in progress:
; (Is this really necessary? I don't think TSR will trigger during PrtSc)
les bx,prtscrn ;ES:bx = pointer to PrtScrn busy flag.
cmp BYTE PTR es:[bx],1 ;Is PrtScrn in progress?
je Exit09 ;If so, try again later.
;
STI ;Allow other interrupts in our TSR.
;
call ROUTINE ;All is clear!, so call routine.
mov hotkeyflag,0 ;Be sure HotKey flag is reset.
jmp SHORT Exit09 ;Exit after TSR routine.
;
SetFlag:
mov hotkeyflag,1 ;Set HotKey Flag for use by Int28h.
;
Exit09:
mov CS:bellgate,0 ;Open gate allowing new HotKey detect.
BusyExit09:
pop es ;Restore all registers
pop ds
ASSUME DS:NOTHING ;v0.01
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
;
;
; Return from this TSR's Keyboard Interrupt 09h handler routine:
iret
;
NewInt09 ENDP ;v0.01
;
;*************************************************************************
PAGE
;*************************************************************************
NewInt13 PROC FAR ;We hook Int13h only for purpose
;of setting a flag to prevent our
;TSR from triggering during time-
;critical Disk accesses.
mov CS:diskflag,1 ;Set flag to show Disk access.
;
pushf ;Invoke prior Int13 handler
cli ;(be sure interrupts disabled)
call CS:oldint13 ;by simulating an interrupt.
;
mov CS:diskflag,0 ;Clear flag to show Disk finished.
;
; The following RET 2 bumps the SP register up by 2 bytes to effectively
; take the flags off the stack (where they were put by the invoking
; INT 13h) WITHOUT popping them off and ruining the meaningful flags
; left in the Flags register by the original DOS INT13 handler (the
; DOS INT13 handler also returns via a RET 2 to keep from ruining the
; Flags that the handler has painstakingly prepared for communicating
; back to the calling program). The effect on the stack pointer, SP, is
; exactly the same as with the more usual IRET. It is just that the Flags
; in the Flag register are preserved at the values the handler placed
; and wanted there.
;
RET 2 ;Return from interrupt while
;preserving flags.
;
NewInt13 ENDP
;*************************************************************************
PAGE
;*************************************************************************
NewInt16 PROC FAR ;v0.01
;
push ds ;Entry for New Int. Handler.
; ;Save required registers.
;
push CS ;Set data seg v0.01
pop DS ;to our CodeSeg v0.01
ASSUME DS:CodeSeg ;v0.01
;
; This next portion of code provides back to the non-resident
; TSR installation code a check on whether the TSR has already been installed.
; It does this through the following technique:
; Check to see if the ax, bx, cx, dx registers are loaded with this
; TSR's signature words. Since all TSR ax signature words are chosen
; so as NOT to match any allowed DOS Int16h Function in ah, ALL
; standard DOS Int16h calls will exit from this sequence of compares
; at the first JNE instruction below and will ultimately be processed
; by the standard DOS Int16h handler.
; The ONLY place where all the registers are loaded with THIS TSR's
; signature words and then Int16h called is IN THE INITIALIZATION CODE
; AT THE END OF THIS TSR. Given that all the signature words are matched
; in the four comparisons below, we need to signal back to the
; invoking TSR initialization code by setting the data registers to
; values that NEVER would be returned by the standard DOS Int16h handler,
; and that therefore could ONLY have come from this previously-installed
; TSR's Int16h handler code. The TSR installation code will then take
; the return of these unique register values as the indication that
; this TSR has already been installed.
;
cmp ax,TSRsigA ;Is ax = TSR signature word A?
jne Exit16 ;No, let regular Int16 handle this.
cmp bx,TSRsigB ;Is bx = TSR signature word B?
jne Exit16 ;No, let regular Int16 handle this.
cmp cx,TSRsigC ;Is cx = TSR signature word C?
jne Exit16 ;No, let regular Int16 handle this.
cmp dx,TSRsigD ;Is dx = TSR signature word D?
jne Exit16 ;No, let regular Int16 handle this.
;
; The ONLY way you ever get to here is by having called Int16h with the
; ax, bx, cx, dx registers loaded with this TSR's signature words. This
; only occurs in the TSR initialization routine. Therefore, set the
; registers to return values that a DOS Int16h never would, and then
; return from this interrupt back to the TSR initialization routine.
;
xchg bx,cx ;Exchange regs. (DOS Int16h wouldn't do this)
xchg ax,dx ; " " "
;
pop ds ;Restore regs.
iret ;Return from Int to TSR Initialize routine.
;
Exit16:
pop ds ;Restore all registers
ASSUME DS:NOTHING ;v0.01
;
; Chain to prior Interrupt 16h handler routine:
jmp CS:oldint16
;
NewInt16 ENDP ;v0.01
;*************************************************************************
PAGE
;*************************************************************************
NewInt28 PROC FAR ;v0.01
;
pushf ;Call prior handler.
cli
call CS:oldint28
;
; Determine if this TSR's HotKey has been flagged as pressed:
cmp CS:hotkeyflag,1 ;Has HotKey been pressed?
jne QuickExit ;Exit if not.
;
cmp CS:bellgate,1 ;Is gate closed?
je QuickExit ;If so, exit.
mov CS:bellgate,1 ;Else close gate and proceed.
;
CLI ;DISABLE INTERRUPTS
; If you are here, then HotKey has been pressed.
push ax ;Entry for New Int. Handler.
push bx ;Save all registers.
push cx
push dx
push si
push di
push bp
push ds
push es
;
push CS
pop DS
ASSUME DS:CodeSeg ;v0.01
;
;
; Make sure InDOS flag is no greater than 1. The InDOS flag equals
; the number of DOS calls currently active. If we want to be sure
; that we do not disrupt DOS by reentry in our TSR user routine,
; we have to be sure that the present Int28 has occurred while
; only 1-deep into DOS calls (as it is when DOS is TRULY idling):
les bx,indosptr ;ES:bx points to InDOS flag.
cmp BYTE PTR ES:[bx],1 ;Is InDOS flag above 1?
ja Exit28 ;Exit if InDOS > 1.
;
; DOS is known to be idling at this point.
; At this point, HotKey is known to have been pressed. Now we will
; check to be sure that no time-critical hardware interrupt handling
; is underway. We do this by querying the Intel 8259A Programmable
; Interrupt Controller (PIC) chip's In Service Register (ISR) and
; testing it to see that it is zero (i.e., nothing being serviced
; except Int09 (PIC's IRQ1) ):
HotKeyPressed2:
mov al,ISRREQ ;al=PIC's OCW3 to ask for ISR Register.
out PICPORT,al ;Tell PIC to get ISR ready for reading.
jmp Dally2 ;Give PIC time to make ISR available.
Dally2: in al,PICPORT ;Fetch the ISR Register from PIC.
;
; Also, don't trigger the TSR if time-critical Disk access is underway:
or al,diskflag ;al = ISR | diskflag. (| => Logical OR).
jnz Exit28 ;If al not zero, try again later.
;
; Also, don't trigger the TSR if a PrtScrn is in progress:
; (Is this really necessary? I don't think TSR will trigger during PrtSc)
les bx,prtscrn ;ES:bx = pointer to PrtScrn busy flag.
cmp BYTE PTR es:[bx],1 ;Is PrtScrn in progress?
je Exit28 ;If so, Exit w/o triggering TSR.
;
STI ;ENABLE OTHER INTERRUPTS.
;
HotKeyFlagSet:
; Here, HotKey is flagged as pressed and DOS is idling (since we are
; servicing Int28h) and no hardware interrupts are being handled.
; Also, no Print Screen or Disk access is underway.
; DOS Int21h Functions above 0Ch can be accessed if required in your
; TSR routine:
;
call ROUTINE ;Call TSR routine; DOSOK & No Hardware
;interrupts being serviced.
mov CS:hotkeyflag,0 ;Clear HotKey Flag.
;
Exit28:
pop es ;Restore all registers
pop ds
ASSUME ds:NOTHING
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov CS:bellgate,0
;
QuickExit:
; Return from this Keyboard Interrupt 28h handler routine:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -