home *** CD-ROM | disk | FTP | other *** search
- ;******************************************************
- ; TPTSR.ASM 5.07
- ; TSR Management routines
- ; Copyright (c) TurboPower Software 1987.
- ; Portions copyright (c) Sunny Hill Software 1985, 1986
- ; and used under license to TurboPower Software
- ; All rights reserved.
- ;******************************************************
-
- INCLUDE TPCOMMON.ASM
-
- ;****************************************************** Equates
-
- MaxScanCode = 86h ;Do not change !!.07
- IfcSignature = 0F0F0h ;Do not change
- IfcSignature2 = 0E0E0h ;Do not change
- NextIfc = 14 ;Offset of NextIfc field in IFC record
-
- ;****************************************************** Data
-
-
- DATA SEGMENT BYTE PUBLIC
-
- ;Pascal variables
-
- EXTRN PopupAddrs : BYTE ;Addresses of popup routines
- EXTRN PopupStacks : BYTE ;Stacks for popup routines
- EXTRN PopupInUse : BYTE ;Flags for popups in use
- EXTRN PopupKeys : BYTE ;Trigger keys for popups
- EXTRN ShiftKeys : BYTE ;Shift keys for popups
- EXTRN DosWaitFlags : BYTE ;Flags popups that need DOS
- EXTRN PopTickerPtr : DWORD ;Points to PopTicker
- EXTRN PopupsEnabledPtr : DWORD ;Points to PopupsEnabled
- EXTRN PopupToCallPtr : DWORD ;Points to PopupToCall
- EXTRN PrefixSeg : WORD ;Our PSP segment
- EXTRN DosVersion : WORD ;Version of DOS
- EXTRN ThisIfc : BYTE ;Standard interface record
- EXTRN IfcInstalled : BYTE ;True if we're in charge of IFC
-
- ;internal variables
-
- DosTrapsSet DB ? ;True if special trapping of DOS
- ;INT vectors, etc. has been done
- LastEntrySS DW ? ;Data needed for EmergencyExit
- LastEntrySP DW ?
- LastEntryIP DW ?
-
- DATA ENDS
-
- ;****************************************************** Code
-
- CODE SEGMENT BYTE PUBLIC
-
- ASSUME CS:CODE,DS:DATA
-
- PUBLIC Int5, Int8, Int9, Int10, Int13, Int14, Int16, Int17, Int25,
- PUBLIC Int26, Int28, Int33, InitTsrPtrs, Int24Result, EmergencyExit
- PUBLIC Save3Fvector, DosBusyFlag, DosCriticalFlag
-
- ;Pascal routines
-
- EXTRN IoResultPrim:NEAR ;Pascal routine
-
- ;Note that these variables are all in the code segment
-
- ;When both of these variables point to zero, DOS may be called
- DosInUsePtr Pointer <> ;Non-0 if DOS is in use
- DosCriticalPtr Pointer <> ;Non-0 if DOS is critical
- HaveDosCritical DB 0 ;Set to 1 if DosCriticalPtr is reliable
-
- ;Old interrupt vectors
- OldInt05 Pointer <> ;Old INT $05 handler (PrtSc)
- OldInt08 Pointer <> ;Old INT $08 handler (clock)
- OldInt09 Pointer <> ;Old INT $09 handler (keyboard)
- OldInt10 Pointer <> ;Old INT $10 handler (video)
- OldInt13 Pointer <> ;Old INT $13 handler (disk)
- OldInt14 Pointer <> ;Old INT $14 handler (comm.)
- OldInt16 Pointer <> ;Old INT $16 handler (keyboard)
- OldInt17 Pointer <> ;Old INT $17 handler (printer)
- OldInt25 Pointer <> ;Old INT $25 handler (abs. disk read)
- OldInt26 Pointer <> ;Old INT $26 handler (abs. disk write)
- OldInt28 Pointer <> ;Old INT $28 handler (DOS multitasking)
- OldInt33 Pointer <> ;Old INT $33 handler (mouse driver)
-
- ;Following needed for TSR's written with TP 5.0
- NewInt34 Pointer <> ;for emulation
- NewInt35 Pointer <>
- NewInt36 Pointer <>
- NewInt37 Pointer <>
- NewInt38 Pointer <>
- NewInt39 Pointer <>
- NewInt3A Pointer <>
- NewInt3B Pointer <>
- NewInt3C Pointer <>
- NewInt3D Pointer <>
- NewInt3E Pointer <>
- NewInt3F Pointer <> ;for overlays
-
- ;Following needed for TSR's that use the 8087
- NewInt02 Pointer <> ;NMI interrupt
- NewInt75 Pointer <> ;8087 exceptions
-
- Int24Err DB 0 ;Boolean -- 1 means critical error
- Int24ErrCode DB 0 ;Byte -- the DOS error code
-
- PopupToCall DB 0 ;Index number of a pending popup
- PopupsEnabled DB 0 ;Boolean, determines if we react to pop keys
- PopTimeOut DW 36 ;Default timeout number of clock ticks
- ;(2 seconds on PC)
- PopTicker DW 0 ;Decremented as the clock ticker
- OurDS DW DATA ;Value of DS -- init'd by EXE loader
- OurDTA Pointer <> ;Our DTA
- OurPSP DW 0 ;Our PSP
- TempTrapFlag DB 0 ;Flag to indicate if traps need setting
- IsEnhanced DB 0 ;1 if it's an enhanced keyboard
-
- Dos3Plus DB True ;Boolean - True if running DOS 3.x or
- ; higher
-
- SystemState DW 0 ;see comment below
- StateFlags EQU WP CS:SystemState ;for convenience
-
- COMMENT @
- When SystemState is zero, popping up is OK. Each interrupt handler has its
- own bit which is set on entry and reset on exit from the interrupt. One
- bit used is set when we are setting/removing the DOS traps.
-
- The bit flags are as follows:
-
- F E D C B A 9 8 7 6 5 4 3 2 1 0 Flag indicates we're inside this INT:
- -------------------------------- -------------------------------------
- | | | | | | | | | | | | | | | +- $05 PrtSc
- | | | | | | | | | | | | | | +--- $08 Clock tick (hardware)
- | | | | | | | | | | | | | +----- $09 Keyboard (hardware)
- | | | | | | | | | | | | +------- $10 BIOS video interrupt
- | | | | | | | | | | | +--------- $13 BIOS disk read/write
- | | | | | | | | | | +----------- $14 BIOS communications
- | | | | | | | | | +------------- $16 BIOS keyboard
- | | | | | | | | +--------------- $17 BIOS printer
- | | | | | | | +----------------- $25 DOS absolute disk read
- | | | | | | +------------------- $26 DOS absolute disk write
- | | | | | +--------------------- $28 DOS multitasking
- | | | | +----------------------- $33 Mouse driver
- | | | +------------------------- -- Setting DOS traps
- +-+-+--------------------------- xxx Bits $D-$F are reserved
- @
-
- ;****************************************************** Bit masks
-
- InInt05 = 0000000000000001b ;Set when in INT $05
- InInt08 = 0000000000000010b ;Set when in INT $08
- InInt09 = 0000000000000100b ;Set when in INT $09
- InInt10 = 0000000000001000b ;Set when in INT $10
- InInt13 = 0000000000010000b ;Set when in INT $13
- InInt14 = 0000000000100000b ;Set when in INT $14
- InInt16 = 0000000001000000b ;Set when in INT $16
- InInt17 = 0000000010000000b ;Set when in INT $17
- InInt25 = 0000000100000000b ;Set when in INT $25
- InInt26 = 0000001000000000b ;Set when in INT $26
- InInt28 = 0000010000000000b ;Set when in INT $28
- InInt33 = 0000100000000000b ;Set when in INT $33
- InSetTR = 0001000000000000b ;Set when we set traps
-
- NotIn05 = 1111111111111110b ;Clears INT $05 flag
- NotIn08 = 1111111111111101b ;Clears INT $08 flag
- NotIn09 = 1111111111111011b ;Clears INT $09 flag
- NotIn10 = 1111111111110111b ;Clears INT $10 flag
- NotIn13 = 1111111111101111b ;Clears INT $13 flag
- NotIn14 = 1111111111011111b ;Clears INT $14 flag
- NotIn16 = 1111111110111111b ;Clears INT $16 flag
- NotIn17 = 1111111101111111b ;Clears INT $17 flag
- NotIn25 = 1111111011111111b ;Clears INT $25 flag
- NotIn26 = 1111110111111111b ;Clears INT $26 flag
- NotIn28 = 1111101111111111b ;Clears INT $28 flag
- NotIn33 = 1111011111111111b ;Clears INT $33 flag
- NotSetTR = 1110111111111111b ;Clears setting traps flag
-
- ;****************************************************** TryPop
-
- COMMENT |
- This procedure checks to see if the system is OK and, if so, calls the
- current popup. It preserves all registers except the flags.
-
- On entry, the stack should look exactly as it did after the interrupt
- occurred, with no other data PUSHed, and the interrupt flag should be
- disabled.
-
- TryPop must not be CALLed; it must be jumped to. When finished, TryPop
- executes an IRET instruction.
-
- TryPop also contains the label DosOkToPop, which the interrupt $28 filter
- jumps to when it needs to pop up.
- |
-
- TryPop PROC NEAR
-
- CLI ;No interrupts between chk and zero
- CMP CS:PopupsEnabled,0 ;make sure popups are enabled
- JZ SysNotOK
- CMP CS:PopTicker,0 ;check this so we can be called without
- ;knowing
- JZ SysNotOK ;if not waiting, just return
- CMP StateFlags,0 ;Check system state
- JE SysOkTryPop ;if not OK, pass on
-
- SysNotOK:
- IRET ;return with non-zero flags
-
- SysOkTryPop:
- MOV CS:PopupsEnabled,0 ;no popups now
- STI ;Interrupts on
- PUSH DS ;Save DS
- PUSH BX ;Save BX
- PUSH AX ;Save AX
-
- MOV DS,CS:OurDS ;get data seg
- SetZero AX ;zero AX
- MOV AL,CS:PopupToCall ;Popup index in AL
- DEC AX ;less 1 for base of 1
- MOV BX,Offset DosWaitFlags ;offset of DosWaitFlags array
- XLAT ;Get value. If not 0, check DOS
- MOV BX,AX ;Store state of the flag in BX
- SUB BL,DosTrapsSet ;BL = (1-0), (1-1), (0-0), or (0-1)
- MOV CS:TempTrapFlag,BL ;Save the result
- OR AX,AX ;check for 0
- JNZ CheckDosOkToPop ;if not 0, check DOS
-
- POP AX ;restore used regs
- POP BX
- POP DS
- JMP SHORT DosOkToPop ;not using DOS, all's well
-
- CheckDosOkToPop:
- LDS BX,CS:DosInUsePtr ;DOS in use pointer in DS:BX
- MOV AL,[BX] ;DOS byte in AL
- LDS BX,CS:DosCriticalPtr ;Check DOS critical flag
- OR AL,[BX] ;they must both be zero
- POP AX ;restore used regs
- POP BX
- POP DS
- JZ DosOkToPop
-
- ExitEnabled:
- MOV CS:PopupsEnabled,1 ;reenable popups
- IRET
-
- ;If we get here then the DISK and DOS are fine.
- DosOkToPop:
- MOV CS:PopTicker,0 ;stop checking period
- STI ;interrupts on
- SaveAllRegs ;Save all registers
- MOV DS,CS:OurDS ;Get data segment
-
- SetZero BX ;Zero BX
- MOV BL,CS:PopupToCall ;Get index of popup
- DEC BX ;PopupAddrs is 1-based
- MOV SI,BX ;save index in SI for now
- SHL BX,1 ;PopupAddrs is array of pointers
- SHL BX,1
-
- PUSH WP PopupAddrs[BX].Segm ;Push segment of popup
- PUSH WP PopupAddrs[BX].Ofst ;Push offset of popup
-
- ;switch stacks
-
- MOV AX,SS ;save current SS in AX
- MOV ES,AX ;ES = current SS
- MOV DX,WP PopupStacks[BX].Segm ;DX = new SS
- MOV BX,WP PopupStacks[BX].Ofst ;BX = new SP
- CLI ;interrupts off
- MOV SS,DX ;new SS in SS
- XCHG BX,SP ;swap new & old SP, old in ES:BX
- STI ;interrupts on
-
- ADD BX,4 ;ES:BX points to Regs,
- ;ES:[BX-4] has pointer to popup
- PUSH ES ;save top of regs segment
- PUSH BX ;and offset
- PUSH SI ;save index of popup
-
- PUSH LastEntrySS ;Save any previous routine's SS
- PUSH LastEntrySP ;SP
- PUSH LastEntryIP ;and reentry offset
-
- PUSH ES ;pass top of regs segment
- PUSH BX ;and offset as VAR parameter
-
- CMP CS:TempTrapFlag,True ;see if traps need to be set
- JE SetTrapsToPop ;If so, use alternate routine
-
- ;Else, save info for emergency exit and call popup
- MOV LastEntrySS,SS ;Save SS
- MOV LastEntrySP,SP ;Save SP
- MOV LastEntryIP,Offset BackInTryPop ;Save reentry offset
-
- MOV CS:PopupsEnabled,1 ;reenable popups
- CallFar ES:[BX-4] ;CALL popup, which will get rid
- ;of the last two PUSH's
- JMP SHORT BackInTryPop ;We're back, clean up
-
- SetTrapsToPop:
- CALL SetDosTraps ;Set the traps and call pop-up
-
- BackInTryPop:
- POP LastEntryIP ;restore previous reentry offset
- POP LastEntrySP ;SP
- POP LastEntrySS ;and previous routine's SS
- POP BX ;index value in BX
-
- MOV PopupInUse[BX],False ;Popup is not in use
- POP BX ;old SP in BX
- POP AX ;old SS in AX
- CLI ;interrupts off
- MOV SS,AX ;restore SS
- MOV SP,BX ;restore SP
- STI ;interrupts on
- RestoreAllRegs ;restore all registers
- IRET ;return to caller
-
- TryPop ENDP
-
- ;****************************************************** DecPopTicker
-
- ;Check to see if we've timed out while waiting to pop up
-
- DecPopTicker PROC NEAR
-
- DEC CS:PopTicker ;Decrement ticker
- JNZ DecDone
-
- PUSH DS ;Timed out, use these regs
- PUSH BX
- MOV DS,CS:OurDS ;get data segment
- SetZero BH ;zero BH
- MOV BL,CS:PopupToCall ;get number of popup
- DEC BX ;array has base of 1, convert to 0 base
- MOV PopupInUse[BX],False ;Popup is not in use
- POP BX ;restore registers
- POP DS
-
- DecDone:
- STI ;interrupts on
- RET
-
- DecPopTicker ENDP
-
- ;****************************************************** Int8
-
- COMMENT |
- Clock interrupt handler.
- ------------------------
- Traps the clock tick to see if it should activate a routine. If it can, it
- clears the clock tick, then calls the appropriate popup. If it can't, it
- chains to the previous INT $8 handler.
- |
-
- TempInt08 Pointer <> ;Temporary address
-
- Int8 PROC NEAR
-
- CMP CS:PopTicker,0 ;Check to see if we're waiting to pop up
- JE Int8Pass ;if not, pass on interrupt
-
- CheckPopClk:
- TEST StateFlags,InInt08 ;check if we're in use
- JZ Int8Try ;if not, try to pop up
- CALL DecPopTicker ;else, see if we timed out
-
- Int8Pass:
- CLI ;interrupts off
- JmpFar CS:OldInt08 ;pass on interrupt
-
- Int8Try:
- OR StateFlags,InInt08 ;now we are in use
- STI ;interrupts on
- POP CS:TempInt08.Ofst ;caller's offset
- POP CS:TempInt08.Segm ;caller's segment
- CLI ;interrupts off
- CALL CS:OldInt08 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- STI ;interrupts on
- PUSHF ;caller's flags on stack
- PUSH CS:TempInt08.Segm ;caller's segment
- PUSH CS:TempInt08.Ofst ;caller's offset on stack
-
- CLI ;interrupts off
- CMP CS:PopTicker,0 ;check again in case it expired
- JZ NoTimeOut ;return
-
- AND StateFlags,NotIn08 ;clear clock-in-use bit
- JNZ CheckTimeOut ;not OK, pass on
- JMP TryPop ;try to pop-up
-
- CheckTimeOut:
- CALL DecPopTicker ;see if we've timed out
-
- NoTimeOut:
- AND StateFlags,NotIn08 ;clear clock-in-use bit
- IRET ;return to caller
-
- Int8 ENDP
-
- ;****************************************************** Int9
-
- COMMENT |
- Keyboard interrupt handler.
- ---------------------------
- Intercepts the keyboard hardware interrupt (INT 9) to determine when we should
- pop up. If the proper mask is active and one of the defined keys is struck,
- then this routine does the following:
-
- - sets PopupToCall to the array index of the key that was struck
- - sets PopTicker to the timeout value
- - resets the keyboard and returns
-
- Int8, Int16, and Int28 take over from there.
- |
-
- TempInt09 Pointer <>
- RoutineNum DB 0
- BiosDataSeg DW 40h
-
- KbdData = 60h
- BiosShiftFlags = 17h
-
- Int9 PROC NEAR
-
- STI ;interrupts on
- PUSH DS ;Save DS
- PUSH AX ;Save AX
- PUSH BX ;Save BX
- MOV DS,CS:BiosDataSeg ;Check BIOS data area
- MOV AH,DS:[BiosShiftFlags] ;BIOS status byte into AH
- AND AH,00001111b ;If none of these flags is set, can't
- ;be a hot key...
- JZ PassKbdInt ;So exit
-
- IN AL,KbdData ;Get key struck
- CMP AL,MaxScanCode ;see if it's in our range
- JA PassKbdInt ;no, pass on
-
- MOV DS,CS:OurDS ;Reset DS
- SetZero BH ;BH = 0
- MOV BL,AL ;BX has index into arrays of bytes
- ;based on scan codes
- MOV AL,PopupKeys[BX] ;get popup handle in AL
- OR AL,AL ;check for 0
- JZ PassKbdInt ;if 0, not a hot key
- CMP AH,ShiftKeys[BX] ;Shift keys match?
- JE AttemptPop ;if so, try to POP up
-
- PassKbdInt:
- POP BX ;Restore BX
- POP AX ;Restore AX
- POP DS ;Restore DS
- TEST StateFlags,InInt09 ;Check if we're in use
- JZ TrackKbd ;if no, set variable
- CLI ;interrupts off
- JmpFar CS:OldInt09 ;else, just pass this on
-
- TrackKbd:
- OR StateFlags,InInt09 ;Set our bit
- POP CS:TempInt09.Ofst ;Offset of caller
- POP CS:TempInt09.Segm ;Segment of caller
- CLI ;interrupts off
- CallFar CS:OldInt09 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;Save flags
- CLI ;Ints off
- PUSH CS:TempInt09.Segm ;Segment of caller
- PUSH CS:TempInt09.Ofst ;Offset of caller
-
- AND StateFlags,NotIn09 ;Reset our bit
- IRET ;return to caller
-
- AttemptPop:
- SetZero AH ;zero in AH
- MOV BX,AX ;get routine handle IN BX
- DEC BX ;array has base of 1
-
- ;make sure it's all right to try to pop up
-
- CLI ;Ints off
- CMP CS:PopupsEnabled,True ;Are popups enabled?
- JNE DontPop ;No? Eat the hotkey
- CMP PopupInUse[BX],AH ;Popup already in use?
- JNE DontPop ;Yes? Eat the hotkey
- CMP CS:PopTicker,0 ;Something else waiting to pop up?
- JNE DontPop ;Yes? Eat the hotkey
-
- ;checks went OK, we can set the pop ticker
-
- MOV PopupInUse[BX],True ;This popup is in use now
- INC BX ;Popup to call in BX
- MOV CS:PopupToCall,BL ;In PopupToCall
- MOV AX,CS:PopTimeOut ;timeout value in AX
- MOV CS:PopTicker,AX ;set PopTicker
- DontPop:
- STI ;interrupts on
- ResetKbd ;reset keyboard (trashes AX)
- NullJump ;delay
- ResetPIC ;reset PIC port (trashes AX)
- POP BX ;Restore BX
- POP AX ;Restore AX
- POP DS ;Restore DS
- IRET
-
- Int9 ENDP
-
- ;****************************************************** Int16
-
- COMMENT |
- BIOS keyboard interrupt handler.
- --------------------------------
- Intercepts the BIOS keyboard interrupt (INT 16) to allow popups to be
- activated while waiting for keyboard input.
-
- Also used to communicate data between TSR's written with Turbo Professional.
- |
-
- TempInt16 Pointer <> ;local
- IntraApp = 00F0h ;offset of intraapplication comm area
-
- Int16 PROC NEAR
-
- STI ;Interrupts on
- CMP AX,IfcSignature ;See if this is a request for info
- JNE NotIfcCheck1 ;If not, continue
- PUSH DS ;Save DS
- MOV DS,CS:OurDs ;DS = OurDS
- CMP IfcInstalled,True ;Are we in charge of the interface?
- POP DS ;Restore DS
- JNE JumpOld16 ;If not, chain to old ISR
- NOT AX ;Flip the bits in AX
- MOV ES,CS:OurDs ;ES = DS
- MOV DI,Offset ThisIfc ;ES:DI points to ThisIfc
- MOV WP ES:[DI].NextIfc,0 ;If we're answering this, we're the end
- MOV WP ES:[DI].NextIfc+2,0 ; of the line, so NextIfc is nil
- IRET
-
- NotIfcCheck1:
- CMP AX,IfcSignature2 ;Is this a secondary request?
- JNE NotIfcCheck
- PUSH DS ;Save DS
- MOV DS,CS:OurDs ;DS = OurDS
- CMP IfcInstalled,True ;Are we in charge of the interface?
- POP DS ;Restore DS
- JNE JumpOld16 ;If not, chain to old ISR
- NOT AX ;Flip the bits in AX
- PUSH ES ;save registers
- PUSH DI
- PUSH BX
- PUSH CX
- MOV CX,BiosDataSeg ;ES:DI => intra-app comm area
- MOV ES,CX
- MOV DI,IntraApp
- MOV CX,CS:OurDs ;CX:BX => ThisIfc
- MOV BX,Offset ThisIfc
- MOV ES:[DI].Ofst,BX ;store @ThisIfc at Ptr(ES,DI)^
- MOV ES:[DI].Segm,CX
- MOV ES,CX ;ES:BX points to ThisIfc
- MOV WP ES:[BX].NextIfc,0 ;If we're answering this, we're the end
- MOV WP ES:[BX].NextIfc+2,0 ; of the line, so NextIfc is nil
- POP CX
- POP BX
- POP DI
- POP ES
- IRET
-
- NotIfcCheck:
- TEST StateFlags,InInt16 ;Check if we're in use
- JZ TrackInt16 ;if not, set variable
-
- JumpOld16:
- CLI ;Interrupts off
- JmpFar CS:OldInt16 ;else, pass this on
-
- TrackInt16:
- CMP AH,10h ;Is it function 10h?
- JE ChkEnhKbd ;If so, use enhanced keyboard code
- OR AH,AH ;check for function 0 (read next char)
- JNZ TrackRaw16 ;if AH <> 0, track INT 16 raw
-
- ChkKbdLoop:
- ;loop until a key is pressed, alternately checking for keyboard
- ;input and trying to pop up
-
- MOV AH,1 ;execute check for keypress function
- OR StateFlags,InInt16 ;Set our bit
-
- POP CS:TempInt16.Ofst ;Offset of caller
- POP CS:TempInt16.Segm ;Segment of caller
-
- CLI ;interrupts off to emulate interrupt
- CallFar CS:OldInt16 ;Call original routine
-
- PUSHF ;save flags
- STI ;interrupts on
- PUSH CS:TempInt16.Segm ;Segment of caller
- PUSH CS:TempInt16.Ofst ;Offset of caller
-
- LAHF ;save return flags
- AND StateFlags,NotIn16 ;Reset our bit
- JNZ ChkKbdLoopNext ;if state isn't clear, don't try
-
- PUSHF ;get set for IRET
- PUSH CS ;push CS (next call is near)
- CALL ChkKbdTryPop ;push return offset too
-
- ;IRET in TryPop returns to here
- JMP SHORT ChkKbdLoopNext ;check again
-
- ChkKbdTryPop:
- JMP TryPop ;try to pop up
-
- ChkKbdLoopNext:
- SAHF ;restore flags
- JZ ChkKbdLoop ;if no key waiting, loop
- SetZero AH ;switch back to function 0, get key
-
- TrackRaw16:
- OR StateFlags,InInt16 ;Set our bit
- POP CS:TempInt16.Ofst ;Offset of caller
- POP CS:TempInt16.Segm ;Segment of caller
- CLI ;interrupts off to emulate interrupt
- CallFar CS:OldInt16 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- STI ;interrupts on
- PUSH CS:TempInt16.Segm ;Segment of caller
- PUSH CS:TempInt16.Ofst ;Offset of caller
-
- ;reset our in-interrupt flag and return
- AND StateFlags,NotIn16 ;Reset our bit
- JNZ RetFromI16 ;if that didn't make state 0, return
-
- JMP TryPop ;try to pop up
-
- RetFromI16:
- IRET
-
- ;the remainder of the ISR allows us to pop up during function $10
- ;calls (the enhanced keyboard version of function 0, read next char)
-
- ChkEnhKbd:
- CMP CS:IsEnhanced,1 ;Is it an enhanced keyboard?
- JNE TrackRaw16 ;If not, don't use the following code!
-
- ChkEnhKbdLoop:
- ;loop until a key is pressed, alternately checking for keyboard
- ;input and trying to pop up
-
- MOV AH,11h ;execute check for keypress function
- OR StateFlags,InInt16 ;Set our bit
-
- POP CS:TempInt16.Ofst ;Offset of caller
- POP CS:TempInt16.Segm ;Segment of caller
-
- CLI ;interrupts off to emulate interrupt
- CallFar CS:OldInt16 ;Call original routine
-
- PUSHF ;save flags
- STI ;interrupts on
- PUSH CS:TempInt16.Segm ;Segment of caller
- PUSH CS:TempInt16.Ofst ;Offset of caller
-
- LAHF ;save return flags
- AND StateFlags,NotIn16 ;Reset our bit
- JNZ ChkEnhKbdLoopNext ;if state isn't clear, don't try
-
- PUSHF ;get set for IRET
- PUSH CS ;push CS (next call is near)
- CALL ChkEnhKbdTryPop ;push return offset too
-
- ;IRET in TryPop returns to here
- JMP SHORT ChkEnhKbdLoopNext ;check again
-
- ChkEnhKbdTryPop:
- JMP TryPop ;try to pop up
-
- ChkEnhKbdLoopNext:
- SAHF ;restore flags
- JZ ChkEnhKbdLoop ;if no key waiting, loop
- MOV AH,10h ;switch back to function 10h, get key
- JMP SHORT TrackRaw16 ;and track it
-
- Int16 ENDP
-
- ;****************************************************** Int28
-
- COMMENT |
- DOS multitasking interrupt handler.
- -----------------------------------
- Handles the DOS multitasking interrupt, which is called continuously at
- the DOS prompt. If PopTicker > 0, this interrupt will call the appropriate
- popup before chaining to the previous INT $28 handler.
- |
-
- TempInt28 Pointer <> ;Temporary address
-
- Int28 PROC NEAR
-
- CLI ;ints off to make sure
- CMP CS:PopTicker,0 ;check pop ticker before doing anything
- JZ I28Pass ;pass if not set
-
- TEST StateFlags,InInt28 ;check if we're in use
- JNZ I28Pass ;if so, pass
-
- ;following needed for Compaq DOS 3.25--calls itself to check for ^Break
- ;during file operations
-
- STI ;interrupts on
- PUSH DS ;Save DS
- PUSH BX ;Save BX
- LDS BX,CS:DosInUsePtr ;DS:BX => DosInUse flag
- CMP BYTE PTR [BX],2 ;BX <= 2?
- JAE Passing ;pass if DosInUse >= 2
- CMP CS:HaveDosCritical,1 ;Do we know where DOS critical flag is?
- JNE NotPassing ;If not, don't check it here
- LDS BX,CS:DosCriticalPtr ;Check DOS critical flag
- CMP BYTE PTR [BX],0 ;is it 0?
- JE NotPassing ;continue if it's 0
- Passing:
- POP BX ;Restore DS
- POP DS ;Restore BX
- JMP SHORT I28Pass
-
- NotPassing:
- POP BX ;Restore DS
- POP DS ;Restore BX
-
- OR StateFlags,InInt28 ;now we're in use
- POP CS:TempInt28.Ofst ;caller's offset
- POP CS:TempInt28.Segm ;caller's segment
- CLI ;interrupts off
- CallFar CS:OldInt28 ;call original routine
-
- PUSHF ;caller's flags on stack
- STI ;interrupts on
- PUSH CS:TempInt28.Segm ;caller's segment
- PUSH CS:TempInt28.Ofst ;caller's offset on stack
-
- CMP CS:PopTicker,0 ;check if we're waiting to pop up
- JNE Go28 ;if so, do it
- AND StateFlags,NotIn28 ;now we're not in use
- IRET
-
- I28Pass:
- CLI ;interrupts off
- JmpFar CS:OldInt28 ;pass to old int 28 handler
-
- Go28:
- PUSH DS ;Save DS
- PUSH BX ;Save BX
- PUSH AX ;Save AX
-
- MOV PopupsEnabled,0 ;disable popups
- MOV DS,CS:OurDS ;get data seg
- SetZero AX ;zero AX
- MOV AL,CS:PopupToCall ;Popup index in AL
- DEC AX ;less 1 for base of 1
- MOV BX,Offset DosWaitFlags ;offset of DosWaitFlags array
- XLAT ;Get value. If not 0, check DOS
- SUB AL,DosTrapsSet ;AL = (1-0), (1-1), (0-0), or (0-1)
- MOV CS:TempTrapFlag,AL ;Save the result
-
- POP AX ;restore used regs
- POP BX
- POP DS
- AND StateFlags,NotIn28 ;now we're not in use
- JMP DosOkToPop ;call routine which won't return
- IRET ;put this here anyhow
-
- Int28 ENDP
-
- COMMENT |
- The remainder of these interrupt handlers are simple filters that prevent
- us from popping up when any one of these interrupts is in progress by setting
- a bit in the system state flag. Their overhead is minimal.
- |
-
- ;****************************************************** Int5
-
- COMMENT |
- PrtSc interrupt handler.
- ------------------------
- Intercepts the PrtSc interrupt to contend with programs that generate the
- interrupt themselves to do screen dumps.
- |
-
- TempInt05 Pointer <> ;local
-
- Int5 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt05 ;Check if we're in use
- JZ TrackInt5 ;if not, set variable
- JmpFar CS:OldInt05 ;yes, pass this on
-
- TrackInt5:
- OR StateFlags,InInt05 ;Set our bit
- POP CS:TempInt05.Ofst ;Offset of caller
- POP CS:TempInt05.Segm ;Segment of caller
- CallFar CS:OldInt05 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt05.Segm ;Segment of caller
- PUSH CS:TempInt05.Ofst ;Offset of caller
-
- ;reset our in-interrupt flag and return
- AND StateFlags,NotIn05 ;Reset our bit
- IRET
-
- Int5 ENDP
-
- ;****************************************************** Int10
-
- COMMENT |
- BIOS video interrupt handler.
- -----------------------------
- Intercepts the BIOS video interrupt to prevent problems when running in
- the OS/2 compatibility box. Not captured if running under DOS 2.x or 3.x.
- |
-
- TempInt10 Pointer <> ;local
-
- Int10 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt10 ;Check if we're in use
- JZ TrackInt10 ;if not, set variable
- JmpFar CS:OldInt10 ;yes, pass this on
-
- TrackInt10:
- OR StateFlags,InInt10 ;Set our bit
- POP CS:TempInt10.Ofst ;Offset of caller
- POP CS:TempInt10.Segm ;Segment of caller
- CallFar CS:OldInt10 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt10.Segm ;Segment of caller
- PUSH CS:TempInt10.Ofst ;Offset of caller
-
- AND StateFlags,NotIn10 ;reset our in-interrupt flag and return
- IRET
-
- Int10 ENDP
-
- ;****************************************************** Int13
-
- COMMENT |
- BIOS disk interrupt handler.
- ----------------------------
- Intercepts the BIOS disk interrupt to contend with programs that bypass DOS
- and access the disk directly.
- |
-
- TempInt13 Pointer <> ;local
-
- Int13 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt13 ;Check if we're in use
- JZ TrackInt13 ;if not, set variable
- JmpFar CS:OldInt13 ;yes, pass this on
-
- TrackInt13:
- OR StateFlags,InInt13 ;Set our bit
- POP CS:TempInt13.Ofst ;Offset of caller
- POP CS:TempInt13.Segm ;Segment of caller
- CallFar CS:OldInt13 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt13.Segm ;Segment of caller
- PUSH CS:TempInt13.Ofst ;Offset of caller
-
- AND StateFlags,NotIn13 ;reset our in-interrupt flag and return
- IRET
-
- Int13 ENDP
-
- ;****************************************************** Int14
-
- COMMENT |
- BIOS communications interrupt handler.
- --------------------------------------
- Intercepts the BIOS communications interrupt to prevent problems when running
- in the OS/2 compatibility box. Not captured if running under DOS 2.x or 3.x.
- |
-
- TempInt14 Pointer <> ;local
-
- Int14 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt14 ;Check if we're in use
- JZ TrackInt14 ;if not, set variable
- JmpFar CS:OldInt14 ;yes, pass this on
-
- TrackInt14:
- OR StateFlags,InInt14 ;Set our bit
- POP CS:TempInt14.Ofst ;Offset of caller
- POP CS:TempInt14.Segm ;Segment of caller
- CallFar CS:OldInt14 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt14.Segm ;Segment of caller
- PUSH CS:TempInt14.Ofst ;Offset of caller
-
- AND StateFlags,NotIn14 ;reset our in-interrupt flag and return
- IRET
-
- Int14 ENDP
-
- ;****************************************************** Int17
-
- COMMENT |
- BIOS printer interrupt handler.
- ------------------------------
- Intercepts the BIOS printer interrupt to prevent problems when running in the
- OS/2 compatibility box. Not captured if running under DOS 2.x or 3.x.
- |
-
- TempInt17 Pointer <> ;local
-
- Int17 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt17 ;Check if we're in use
- JZ TrackInt17 ;if not, set variable
- JmpFar CS:OldInt17 ;yes, pass this on
-
- TrackInt17:
- OR StateFlags,InInt17 ;Set our bit
- POP CS:TempInt17.Ofst ;Offset of caller
- POP CS:TempInt17.Segm ;Segment of caller
- CallFar CS:OldInt17 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt17.Segm ;Segment of caller
- PUSH CS:TempInt17.Ofst ;Offset of caller
-
- AND StateFlags,NotIn17 ;reset our in-interrupt flag and return
- IRET
-
- Int17 ENDP
-
- ;****************************************************** Int25
-
- COMMENT |
- DOS absolute disk read interrupt handler.
- -----------------------------------------
- Intercepts the absolute disk read interrupt to contend with programs
- that use this interrupt.
- |
-
- TempInt25 Pointer <> ;local
-
- Int25 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt25 ;Check if we're in use
- JZ TrackInt25 ;if not, set variable
- JmpFar CS:OldInt25 ;yes, pass this on
-
- TrackInt25:
- OR StateFlags,InInt25 ;Set our bit
- POP CS:TempInt25.Ofst ;Offset of caller
- POP CS:TempInt25.Segm ;Segment of caller
- CallFar CS:OldInt25 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt25.Segm ;Segment of caller
- PUSH CS:TempInt25.Ofst ;Offset of caller
-
- AND StateFlags,NotIn25 ;reset our in-interrupt flag and return
- IRET
-
- Int25 ENDP
-
- ;****************************************************** Int26
-
- COMMENT |
- DOS absolute disk write interrupt handler.
- -----------------------------------------
- Intercepts the absolute disk write interrupt to contend with programs
- that use this interrupt.
- |
-
- TempInt26 Pointer <> ;local
-
- Int26 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt26 ;Check if we're in use
- JZ TrackInt26 ;if not, set variable
- JmpFar CS:OldInt26 ;yes, pass this on
-
- TrackInt26:
- OR StateFlags,InInt26 ;Set our bit
- POP CS:TempInt26.Ofst ;Offset of caller
- POP CS:TempInt26.Segm ;Segment of caller
- CallFar CS:OldInt26 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt26.Segm ;Segment of caller
- PUSH CS:TempInt26.Ofst ;Offset of caller
-
- AND StateFlags,NotIn26 ;reset our in-interrupt flag and return
- IRET
-
- Int26 ENDP
-
- ;****************************************************** Int33
-
- COMMENT |
- Mouse driver interrupt
- ----------------------
- Intercepts mouse driver calls to contend with programs that use this
- interrupt.
- |
-
- TempInt33 Pointer <> ;local
-
- Int33 PROC NEAR
-
- CLI ;Just in case it wasn't called properly
- TEST StateFlags,InInt33 ;Check if we're in use
- JZ TrackInt33 ;if not, set variable
- JmpFar CS:OldInt33 ;yes, pass this on
-
- TrackInt33:
- OR StateFlags,InInt33 ;Set our bit
- POP CS:TempInt33.Ofst ;Offset of caller
- POP CS:TempInt33.Segm ;Segment of caller
- CallFar CS:OldInt33 ;Call original routine
-
- ;Push flags and address on the stack so we can use IRET to return
- PUSHF ;save flags
- CLI ;interrupts off
- PUSH CS:TempInt33.Segm ;Segment of caller
- PUSH CS:TempInt33.Ofst ;Offset of caller
-
- AND StateFlags,NotIn33 ;reset our in-interrupt flag and return
- IRET
-
- Int33 ENDP
-
- ;****************************************************** Save3Fvector
-
- Save3Fvector PROC NEAR
-
- GetVector 3Fh, CS:NewInt3F ;for overlays
- RET
-
- Save3Fvector ENDP
-
- ;****************************************************** InitTsrPtrs
-
- ;procedure InitTsrPtrs;
-
- ;Initializes pointers to hidden variables and pointers that indicate when
- ;DOS is active.
-
- InitTsrPtrs PROC NEAR
-
- ;initialization
- MOV DosTrapsSet,False ;DOS traps not set
- DosCall 2Fh ;Get current DTA
- SetPtr CS:OurDTA, ES, BX ;Save our DTA (in ES:BX)
- MOV AX,PrefixSeg ;AX = our PSP
- MOV CS:OurPSP,AX ;Save in CS-relative storage
-
- ;check to see if it's an enhanced keyboard
- MOV AX,40h ;check bit 4 of byte at $40:$96
- MOV ES,AX
- MOV DI,96h
- TEST BYTE PTR ES:[DI],00010000b
- JZ EnhDone ;if bit is set, it's enhanced
- MOV CS:IsEnhanced,True ;Store CS-relative variable
- EnhDone:
-
- ;allow Pascal routines access to CS-relative data
- SetPtrByOfst PopTickerPtr, CS, PopTicker
- SetPtrByOfst PopupsEnabledPtr, CS, PopupsEnabled
- SetPtrByOfst PopupToCallPtr, CS, PopupToCall
-
- ;Get current interrupt vectors
-
- GetVector 02h, CS:NewInt02 ;NMI interrupt
- GetVector 05h, CS:OldInt05 ;PrtSc interrupt
- GetVector 08h, CS:OldInt08 ;Clock tick interrupt
- GetVector 09h, CS:OldInt09 ;Keyboard interrupt
- GetVector 10h, CS:OldInt10 ;Video interrupt
- GetVector 13h, CS:OldInt13 ;Disk interrupt
- GetVector 14h, CS:OldInt14 ;Comm. interrupt
- GetVector 16h, CS:OldInt16 ;Keyboard interrupt
- GetVector 17h, CS:OldInt17 ;Printer interrupt
- GetVector 25h, CS:OldInt25 ;Disk read interrupt
- GetVector 26h, CS:OldInt26 ;Disk write interrupt
- GetVector 28h, CS:OldInt28 ;DOS multitasking interrupt
- GetVector 33h, CS:OldInt33 ;Mouse driver interrupt
- GetVector 34h, CS:NewInt34 ;for emulation
- GetVector 35h, CS:NewInt35
- GetVector 36h, CS:NewInt36
- GetVector 37h, CS:NewInt37
- GetVector 38h, CS:NewInt38
- GetVector 39h, CS:NewInt39
- GetVector 3Ah, CS:NewInt3A
- GetVector 3Bh, CS:NewInt3B
- GetVector 3Ch, CS:NewInt3C
- GetVector 3Dh, CS:NewInt3D
- GetVector 3Eh, CS:NewInt3E
- GetVector 75h, CS:NewInt75 ;8087 exception ???
-
- ;Get the DOS version
-
- DosCall 30h ;Get DOS version
- XCHG AL,AH ;Major version # in AH, minor in AL
- MOV DosVersion,AX ;Save for the Pascal code
-
- ;Get address of the In-DOS flag
-
- PUSH DS ;Save DS
- DosCall 34h ;Undocumented call to get pointer to
- ;In-DOS flag -- returned in ES:BX
- POP DS ;Restore DS
- SetPtr CS:DosInUsePtr, ES, BX ;Set DOS-in-use pointer
-
- ;Determine the address of the DOS critical pointer based on DOS version
-
- SetZero CX ;Assume failure
- MOV AX,DosVersion ;Get DosVersion back into AX
- CMP AX,0200h ;Check for range 2.00 - 2.$FF
- JB InitDosExit ;Exit with error if < 2.00
- CMP AX,0300h ;Check for 3.00
- JA Dos3x ;If higher, need extra checks
- JB Dos2 ;If less, it's DOS 2.x
-
- CMP BX,019Ch ;Is this Compaq DOS 3.0?
- JE DecOffset ;If so, critical flag below InDos
- SUB BX,01AAh ;Else, this is MS/PC-DOS 3.0
- JMP SHORT SetCriticalPtr ;Ready
-
- Dos2:
- MOV CS:Dos3Plus,False ;Not running DOS 3.x or above
- INC BX ;Critical pointer after in-use pointer
- JMP SHORT SetCriticalPtr ;Ready
-
- Dos3x:
- CMP AX,030Ah ;Check for 3.10 or higher
- JB SetCriticalPtr ;This shouldn't happen
- CMP AX,0363h ;If <=, DOS version is 3.10-3.99
- JA SetCriticalPtr ;Higher version -- presumably OS/2
- ;set DosCriticalPtr = DosInUsePtr
-
- DecOffset:
- DEC BX ;Critical pointer before in-use pointer
-
- SetCriticalPtr:
- INC CX ;Set success flag
- SetPtr CS:DosCriticalPtr, ES, BX ;Set DOS critical pointer
-
- InitDosExit:
- MOV AX,CX ;Result into AX
- RET
-
- InitTsrPtrs ENDP
-
- ;****************************************************** Int24
-
- ;procedure Int24
- ;Interrupt handler for DOS critical errors
-
- FailCode = 3
- IgnoreCode = 0
-
- Int24 PROC NEAR
-
- MOV CS:Int24Err,True ;Set error flag
- XCHG AX,DI ;DI has error code on entry
- MOV CS:Int24ErrCode,AL ;Store error code for later
- XCHG AX,DI ;Restore AX
- MOV AL,FailCode ;Fail the DOS call
- CMP CS:Dos3Plus,True ;DOS 3.x or higher?
- JE Int24Exit ;If so, done
- MOV AL,IgnoreCode ;else, tell DOS to I)gnore error instead
- Int24Exit:
- IRET
-
- Int24 ENDP
-
- ;****************************************************** Int24Result
-
- ;function Int24Result : Word;
- ;Returns word in AX. AH has Int24ErrCode, AL has IoResult.
-
- Int24Result PROC FAR
-
- CALL IoResultPrim ;Get IoResult into AL
- SetZero AH ;Clear AH
- CMP CS:Int24Err,True ;Critical error flag set?
- JNE Int24ResultExit ;No? Done
-
- ;Merge critical error code into result
-
- MOV AH,CS:Int24ErrCode ;Int24ErrCode into AH
- OR AH,AH ;Is AH 0?
- JNZ IrAHnot0 ;If not, continue
- MOV AH,0Dh ;Else, attempt to write to
- ;write protected disk. Map to $0D.
- IrAHnot0:
- MOV CS:Int24ErrCode,0 ;Reset Int24ErrCode to 0
- MOV CS:Int24Err,False ;Clear error flag
-
- Int24ResultExit:
- RET
-
- Int24Result ENDP
-
- ;****************************************************** NopISR
-
- NopISR PROC NEAR
-
- IRET ;For dummy ISR's
-
- NopISR ENDP
-
- ;****************************************************** UseCritical
-
- ;Force DOS 2.x to use DOS critical stack when getting/setting PSP
-
- UseCritical PROC NEAR
-
- CMP CS:Dos3Plus,True ;Is this DOS 3.x?
- JE UCexit ;if so, do nothing
- LES DI,CS:DosCriticalPtr ;ES:DI => DosCriticalPtr
- MOV BYTE PTR ES:[DI],-1 ;Tell DOS to use critical stack
- UCexit:
- RET
-
- UseCritical ENDP
-
- ;****************************************************** NotCritical
-
- ;Reset DOS 2.x for non-critical stack
-
- NotCritical PROC NEAR
-
- CMP CS:Dos3Plus,True ;Is this DOS 3.x?
- JE NCexit ;if so, do nothing
- LES DI,CS:DosCriticalPtr ;ES:DI => DosCriticalPtr
- MOV BYTE PTR ES:[DI],0 ;Tell DOS to use non-critical stack
- NCexit:
- RET
-
- NotCritical ENDP
-
- ;****************************************************** SetDosTraps
-
- COMMENT |
-
- SetDosTraps
- -----------
- Makes preparations to insure that DOS is safe to use during a popup:
-
- -- Saves and restores current DTA and PSP, switching to ours in between
- -- Prevents ^Break/^C problems by taking over dangerous interrupts
- and changing the DOS BREAK level, restoring them after the call
- -- Sets up DOS critical error handler for the popup
-
- After these preparations have been made, the popup is called. Reentrancy
- problems are avoided by means of the DosTrapsSet flag, which prohibits
- this code from being executed twice before the first session is over.
- |
-
- SaveBreak DB 0 ;Saved ^Break state
- SavePSP DW 0 ;Saved PSP segment
- SaveInt02 Pointer <> ;Saved vectors
- SaveInt1B Pointer <>
- SaveInt23 Pointer <>
- SaveInt24 Pointer <>
- SaveInt34 Pointer <>
- SaveInt35 Pointer <>
- SaveInt36 Pointer <>
- SaveInt37 Pointer <>
- SaveInt38 Pointer <>
- SaveInt39 Pointer <>
- SaveInt3A Pointer <>
- SaveInt3B Pointer <>
- SaveInt3C Pointer <>
- SaveInt3D Pointer <>
- SaveInt3E Pointer <>
- SaveInt3F Pointer <>
- SaveInt75 Pointer <>
- SaveDTA Pointer <> ;Saved DTA
- OurReturn DW 0 ;Our return address
- OurCall Pointer <> ;The address we're supposed to call
-
- SetDosTraps PROC NEAR
-
- OR StateFlags,InSetTR ;setting DOS traps
- MOV DosTrapsSet,True ;next time sys ok, DOS traps are set
- MOV CS:PopupsEnabled,1 ;reenable popups
-
- MOV AX,CS ;AX = CS
- MOV DS,AX ;DS = CS
-
- assume DS:CODE ;Tell MASM that DS = CS
-
- POP OurReturn ;POP our return address off the stack
-
- ;save the address we're supposed to call (at ES:[BX-4])
- LES BX,ES:[BX-4] ;Get the address
- SetPtr OurCall, ES, BX ;And save it
-
- DosCallAX 3300h ;Get current BREAK level
- MOV SaveBreak,DL ;Save current level, returned in DL
- SetZero DL ;0 means relax break checking
- DosCallAX 3301h ;Set BREAK value in DL
-
- ;save interrupt vectors we're taking over
- GetVector 02h, SaveInt02
- GetVector 1Bh, SaveInt1B
- GetVector 23h, SaveInt23
- GetVector 24h, SaveInt24
- GetVector 34h, SaveInt34
- GetVector 35h, SaveInt35
- GetVector 36h, SaveInt36
- GetVector 37h, SaveInt37
- GetVector 38h, SaveInt38
- GetVector 39h, SaveInt39
- GetVector 3Ah, SaveInt3A
- GetVector 3Bh, SaveInt3B
- GetVector 3Ch, SaveInt3C
- GetVector 3Dh, SaveInt3D
- GetVector 3Eh, SaveInt3E
- GetVector 3Fh, SaveInt3F
- GetVector 75h, SaveInt75
-
- ;grab control of potentially dangerous interrupts
- MOV DX,Offset NopIsr ;DS:DX to points to IRET
- DosCallAX 251Bh ;BIOS ^Break handler
- DosCallAX 2523h ;DOS ^C handler
-
- ;set up our Int24 handler
- MOV DX,Offset Int24 ;DS:DX points to Int24
- DosCallAX 2524h ;Set critical error handler
-
- ;Restore Turbo's interrupt handlers
- LDS DX,CS:NewInt02
- DosCallAX 2502h
- LDS DX,CS:NewInt34
- DosCallAX 2534h
- LDS DX,CS:NewInt35
- DosCallAX 2535h
- LDS DX,CS:NewInt36
- DosCallAX 2536h
- LDS DX,CS:NewInt37
- DosCallAX 2537h
- LDS DX,CS:NewInt38
- DosCallAX 2538h
- LDS DX,CS:NewInt39
- DosCallAX 2539h
- LDS DX,CS:NewInt3A
- DosCallAX 253Ah
- LDS DX,CS:NewInt3B
- DosCallAX 253Bh
- LDS DX,CS:NewInt3C
- DosCallAX 253Ch
- LDS DX,CS:NewInt3D
- DosCallAX 253Dh
- LDS DX,CS:NewInt3E
- DosCallAX 253Eh
- LDS DX,CS:NewInt3F
- DosCallAX 253Fh
- LDS DX,CS:NewInt75
- DosCallAX 2575h
- MOV AX,CS ;Reset DS to CS
- MOV DS,AX
-
- ;save current DTA and switch to ours
- DosCall 2Fh ;Get current DTA
- SetPtr SaveDTA, ES, BX ;Save current DTA (in ES:BX)
- LDS DX,OurDTA ;DS:DX points to our DTA
- DosCall 1Ah ;Set DTA
-
- assume DS:NOTHING ;we don't know what ds is
-
- ;save current PSP and switch to ours
- CALL UseCritical ;Switch to critical stack in DOS 2.x
- DosCallAX 5100h ;Get current PSP
- MOV CS:SavePSP,BX ;Save PSP returned in BX
- MOV BX,CS:OurPSP ;Get our PSP
- DosCallAX 5000h ;Switch to our PSP
- CALL NotCritical ;Critical stack no longer needed
-
- ;reset DS to DATA
- MOV DS,CS:OurDS ;Restore our DS
- assume DS:DATA ;Tell MASM that DS = DATA
-
- ;Save info for emergency exit and call the popup
- MOV LastEntrySS,SS ;Save SS
- MOV LastEntrySP,SP ;Save SP
- MOV LastEntryIP,Offset SDTReentry ;Save reentry offset
-
- ;make popup look like main block to the overlay manager
- XOR BP,BP ;BP = 0
-
- AND StateFlags,NotSetTR ;done setting DOS traps
- CallFar OurCall ;Call the popup
- OR StateFlags,InSetTR ;resetting DOS traps
-
- SDTReentry:
- ;reset DS to CS and PUSH our return address back on the stack
- MOV AX,CS ;Set DS to CS
- MOV DS,AX
- assume DS:CODE ;Tell MASM that DS = CS
-
- PUSH OurReturn ;PUSH the return address back up
-
- ;restore saved PSP
- CALL UseCritical ;Switch to critical stack in DOS 2.x
- MOV BX,SavePSP ;BX = saved PSP
- DosCallAX 5000h ;Set PSP function
- CALL NotCritical ;Critical stack no longer needed
-
- ;restore saved DTA
- LDS DX,SaveDTA ;DS:DX points to saved DTA
- DosCall 1Ah ;Set DTA function
-
- assume DS:NOTHING ;Tell MASM that DS = ?
-
- ;restore saved interrupt vectors
- LDS DX,CS:SaveInt02
- DosCallAX 2502h
- LDS DX,CS:SaveInt1B
- DosCallAX 251Bh
- LDS DX,CS:SaveInt23
- DosCallAX 2523h
- LDS DX,CS:SaveInt24
- DosCallAX 2524h
- LDS DX,CS:SaveInt34
- DosCallAX 2534h
- LDS DX,CS:SaveInt35
- DosCallAX 2535h
- LDS DX,CS:SaveInt36
- DosCallAX 2536h
- LDS DX,CS:SaveInt37
- DosCallAX 2537h
- LDS DX,CS:SaveInt38
- DosCallAX 2538h
- LDS DX,CS:SaveInt39
- DosCallAX 2539h
- LDS DX,CS:SaveInt3A
- DosCallAX 253Ah
- LDS DX,CS:SaveInt3B
- DosCallAX 253Bh
- LDS DX,CS:SaveInt3C
- DosCallAX 253Ch
- LDS DX,CS:SaveInt3D
- DosCallAX 253Dh
- LDS DX,CS:SaveInt3E
- DosCallAX 253Eh
- LDS DX,CS:SaveInt3F
- DosCallAX 253Fh
- LDS DX,CS:SaveInt75
- DosCallAX 2575h
-
- ;restore DOS BREAK level
- MOV AX,CS ;Reset DS to CS
- MOV DS,AX
- assume DS:CODE ;Tell MASM that DS = CS
-
- MOV DL,SaveBreak ;Restore saved break state
- DosCallAX 3301h ;Set break check level
-
- MOV Int24Err,False ;Don't leave error flag set
-
- SetTrapExit:
- MOV DS,CS:OurDS ;Restore our DS
- assume DS:DATA ;Tell MASM that DS = DATA
-
- MOV DosTrapsSet,False ;DOS traps are not set now
- AND StateFlags,NotSetTR ;not setting DOS traps now
-
- RET
-
- SetDosTraps ENDP
-
- ;****************************************************** EmergencyExit
-
- ;Called by exit/error handler in case of runtime error while popped up
-
- EmergencyExit PROC NEAR
-
- CLI ;Interrupts off
- MOV SS,LastEntrySS ;Switch stacks
- MOV SP,LastEntrySP
- STI ;Interrupts on
- ADD SP,4 ;Get rid of the parameter to the popup
- MOV BX,LastEntryIP ;Jump to re-entry point
- JMP BX
-
- EmergencyExit ENDP
-
- ;****************************************************** DosBusyFlag
-
- ;function DosBusyFlag : Byte;
- ;Returns current value of DOS busy flag
-
- DosBusyFlag PROC FAR
-
- GetPtr CS:DosInUsePtr ;ES:DI => DosInUsePtr
- MOV AL,ES:[DI] ;value into AL
- RET
-
- DosBusyFlag ENDP
-
- ;****************************************************** DosCriticalFlag
-
- ;function DosCriticalFlag : Byte;
- ;Returns current value of DOS critical flag
-
- DosCriticalFlag PROC FAR
-
- GetPtr CS:DosCriticalPtr ;ES:DI => DosCriticalPtr
- MOV AL,ES:[DI] ;value into AL
- RET
-
- DosCriticalFlag ENDP
-
- CODE ENDS
-
- END