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 + -
显示快捷键?