handlers.asm
来自「这是一些例程」· 汇编 代码 · 共 1,284 行 · 第 1/4 页
ASM
1,284 行
;* CtrlC - Interrupt trap for Interrupt 23h (CTRL+C Handler).
;* Disables CTRL+C processing.
;*
;* Params: None
;*
;* Return: None
CtrlC PROC FAR
iret
CtrlC ENDP
;* CritError - Interrupt trap for Interrupt 24h (Critical Error Handler).
;* Disables critical error processing.
;*
;* Params: None
;*
;* Return: AL = Stop code 0 or 3
CritError PROC FAR
sti
sub al, al ; Assume DOS 2.x
; Set AL = 0 for ignore error
.IF cs:major != 2 ; If DOS 3.x, set AL = 3
mov al, 3 ; DOS call fails
.ENDIF
iret
CritError ENDP
;* Idle - Interrupt handler for Interrupt 28h (DOS Idle). Allows the
;* original Interrupt 28h service routine to execute. Then checks the
;* request flag TsrRequestFlag maintained either by the keyboard handler
;* (keyboard-activated TSR) or by the timer handler (time-activated TSR).
;* See header comments above for Clock, Keybrd, and MiscServ procedures.
;*
;* If TsrRequestFlag = TRUE and system is in interruptable state, Idle
;* invokes the TSR by calling the Activate procedure. Uses an active flag
;* to prevent the Idle procedure from being reentered while executing.
;*
;* Uses: intIdle and TsrActiveFlag
;*
;* Params: None
;*
;* Return: None
Idle PROC FAR
pushf ; Simulate interrupt by pushing flags,
call cs:intIdle.OldHand ; far-calling old Int 28h routine
.IF cs:intIdle.Flag == FALSE; If not already in this handler,
mov cs:intIdle.Flag, TRUE ; set active flag
sti ; Interrupts are okay
push ds ; Save application's DS
push cs
pop ds ; Set DS to resident code segment
ASSUME ds:@code
call CheckRequest ; Check conditions
.IF !carry? ; If TSR requested and safe,
mov TsrActiveFlag, TRUE ; activate TSR
call Activate
mov TsrActiveFlag, FALSE
.ENDIF ; End carry flag check
mov intIdle.Flag, FALSE ; Clear active flag
pop ds ; Recover application's DS
.ENDIF ; End in-handler check
iret
Idle ENDP
;* Multiplex - Handler for Interrupt 2Fh (Multiplex Interrupt). Checks
;* AH for this TSR's identity number. If no match (indicating call is
;* not intended for this TSR), Multiplex passes control to the previous
;* Interrupt 2Fh handler.
;*
;* Params: AH = Handler identity number
;* AL = Function number 0-2
;*
;* Return: AL = 0FFh (function 0)
;* ES:DI = Pointer to identifier string (function 0)
;* ES:DI = Pointer to resident PSP segment (function 1)
;* ES:DI = Pointer to shared memory (function 2)
Multiplex PROC FAR
.IF ah != cs:IDnumber ; If this handler not requested,
jmp cs:intMultex.OldHand ; pass control to old Int 2Fh
.ENDIF ; handler
.IF al == 0 ; If function 0 (verify presence),
mov al, 0FFh ; AL = 0FFh,
push cs ; ES = resident code segment
pop es
mov di, OFFSET IDstring ; DI = offset of identifier string
.ELSEIF al == 1 ; If function 1 (get PSP address),
mov es, cs:TsrPspSeg ; ES:DI = far address of resident PSP
sub di, di
.ELSE
les di, cs:ShareAddr ; If function 2 (get shared memory),
.ENDIF ; set ES:DI = far address
NoMultiplex LABEL FAR ; Secondary entry for null Multiplex
iret
Multiplex ENDP
;* CheckHotKey - Checks current keystroke for hot key. Called from Keybrd
;* handler if IBM PC/AT or compatible, or from MiscServ handler if PS/2.
;*
;* Uses: HotScan, HotShift, HotMask, and SHFT_STAT
;*
;* Params: AL = Scan code
;*
;* Return: Carry flag set = FALSE; carry flag clear = TRUE
CheckHotKey PROC NEAR
cmp al, cs:HotScan ; If current scan code isn't code
jne e_exit ; for hot key, exit with carry set
push es ; Else look into BIOS data area
sub ax, ax ; (segment 0) to check shift state
mov es, ax
mov al, es:[SHFT_STAT] ; Get SHIFT-key flags
and al, cs:HotMask ; AND with "don't care" mask
cmp al, cs:HotShift ; Compare result with hot SHIFT key
pop es
je exit ; If match, exit with carry clear
e_exit: stc ; Set carry if not hot key
exit: ret
CheckHotKey ENDP
;* CheckRequest - Checks request flag and system status using the
;* following logic:
;*
;* IF (TsrRequestFlag AND (NOT TsrActiveFlag)
;* AND DosStatus AND HardwareStatus)
;* return TRUE
;* ELSE
;* return FALSE
;*
;* Uses: TsrRequestFlag and TsrActiveFlag
;*
;* Params: DS = Resident code segment
;*
;* Return: Carry flag set = TRUE; carry flag clear = FALSE
CheckRequest PROC NEAR
rol TsrRequestFlag, 1 ; Rotate high bit into carry - set
; if TRUE (-1), clear if FALSE (0)
cmc ; NOT carry
.IF !carry? ; If TsrRequestFlag = TRUE:
ror TsrActiveFlag, 1 ; Rotate low bit into carry - set
; if TRUE (-1), clear if FALSE (0)
.IF !carry? ; If TsrActiveFlag = FALSE:
call CheckDos ; Is DOS in interruptable state?
.IF !carry? ; If so,
call CheckHardware ; if hardware or BIOS unstable,
.ENDIF ; set carry and exit
.ENDIF
.ENDIF
ret
CheckRequest ENDP
;* CheckDos - Checks status of MS-DOS using the following logic:
;*
;* IF (NOT CritErr) AND ((NOT InDos) OR (Idle AND InDos))
;* return DosStatus = TRUE
;* ELSE
;* return DosStatus = FALSE
;*
;* Uses: CritErrAddr, InDosAddr, and intIdle
;*
;* Params: DS = Resident code segment
;*
;* Return: Carry flag set if MS-DOS is busy
CheckDos PROC NEAR USES es bx ax
les bx, CritErrAddr
mov ah, es:[bx] ; AH = value of CritErr flag
les bx, InDosAddr
mov al, es:[bx] ; AL = value of InDos flag
sub bx, bx ; BH = 0, BL = 0
cmp bl, intIdle.Flag ; Carry flag set if call is from
; Interrupt 28h handler
rcl bl, 1 ; Rotate carry into BL: TRUE if Idle
cmp bx, ax ; Carry flag clear if CritErr = 0
; and InDos <= BL
ret
CheckDos ENDP
;* CheckHardware - Checks status of BIOS and hardware using the
;* following logic:
;*
;* IF HardwareActive OR KeybrdActive OR VideoActive OR DiskIOActive
;* return HardwareStatus = FALSE
;* ELSE
;* return HardwareStatus = TRUE
;*
;* Uses: intKeybrd, intVideo, and intDiskIO
;*
;* Params: DS = Resident code segment
;*
;* Return: Carry flag set if hardware or BIOS is busy
CheckHardware PROC NEAR USES ax
; Verify hardware interrupt status by interrogating Intel 8259A
; Programmable Interrupt Controller
mov ax, 00001011y ; AL = 0CW3 for Intel 8259A
; (RR = 1, RIS = 1)
out 20h, al ; Request 8259A in-service register
jmp delay ; Wait a few cycles
delay:
in al, 20h ; AL = hardware interrupts being
cmp ah, al ; serviced (bit = 1 if in service)
.IF !carry? ; If no hard interrupts in service,
sub al, al ; verify BIOS interrupts not active,
cmp al, intKeybrd.Flag ; check Interrupt 09 handler
.IF !carry? ; If Int 09 not active,
cmp al, intVideo.Flag ; check Interrupt 10h handler
.IF !carry? ; If Int 10h not active,
cmp al, intDiskIO.Flag ; check Interrupt 13h handler,
.ENDIF ; return with carry set if
.ENDIF ; Interrupt 09, 10h, or 13h
.ENDIF ; is active
ret
CheckHardware ENDP
;* Activate - Sets up for far call to TSR with the following steps:
;*
;* 1. Stores stack pointer SS:SP and switches to new stack
;* 2. Pushes registers onto new stack
;* 3. Stores vectors for Interrupts 1Bh, 23h, and 23h, and
;* replaces them with addresses of error-trapping handlers
;* 4. Stores DOS CTRL+C checking flag, then turns off checking
;* 5. If required, stores DTA address and switches to new DTA
;*
;* When TSR returns, restores all the above.
;*
;* Uses: Reads or writes the following globals:
;* OldStackAddr, TrapArray, BreakCheckFlag, TsrRequestFlag
;*
;* Params: DS = Resident code segment
;*
;* Return: None
Activate PROC NEAR
; Step 1. Set up a new stack
mov WORD PTR OldStackAddr[0], sp ; Save current
mov WORD PTR OldStackAddr[2], ss ; stack pointer
cli ; Turn off interrupts while
push cs ; changing stack
pop ss ; New stack begins
mov sp, OFFSET NewStack ; at LABEL NewStack
sti
; Step 2. Preserve registers (DS already saved in Clock or Idle)
push ax
push bx
push cx
push dx
push si
push di
push bp
push es
cld ; Clear direction flag
; Step 3. Set up trapping handlers for keyboard breaks and DOS
; critical errors (Interrupts 1Bh, 23h, and 24h)
mov cx, CTRAP ; CX = number of handlers
mov si, OFFSET TrapArray ; DS:SI points to trap array
.REPEAT
mov al, [si] ; AL = interrupt number
mov ah, 35h ; Request DOS Function 35h
int 21h ; Get interrupt vector (ES:BX)
mov WORD PTR [si].INTR.OldHand[0], bx ; Save far address of
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?