home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- ;Preamble:
- ; Received this file from Raymond Michels, author of "Undocumented
- ;DOS Internals," (1989 Programmers' Journal 7.2, pp. 32-37).
- ; Although it makes no mention, it clearly builds on TSRDEMO2.ASM
- ;that is authored by Thomas Brandenborg (Lundbyesgade 11, DK-8000
- ;Aarhus C., DENMARK) which is shareware found on Channel 1 BBS (617-354-
- ;8873, Boston)
- ; There are a few notable differences between the two:
- ; 1. DEMO only went so far as to popup a message while this program
- ; will free 192K of memory used by the current application and then run
- ; another program in that space (NOTE: this program should not be;
- ; confused with SWAP being distributed as SWAPIT.ZIP by Nico Mak,
- ; Mansfield Software Group, Storrs,CT and described in Dr. Dobbs
- ; April, 1989)
- ; 2. SWAP handles screen storage and restoration
- ; 3. SWAP adds scrolldown and scrollup in SCAN Codes
- ; 4. SWAP adds an sti (opcode) in OurInt13 just after the
- ; call OldInt13
- ; 5. SWAP adds a deinstall TSR routine
- ; 6. SWAP modifies handling of ^C with addition of PrevInt23 variable
- ; 7. SWAP changes messages in general
- ; 8. SWAP adds routine CLS to clear screen
- ; 9. SWAP adds saving of screen mode (@ IsColor:)
- ; 10. SWAP removed treatment of EnvSeg at very end
- ;
- ; W. Curtiss Priest, Humanic Systems
- ; Lexington, MA, 02173
- ;
-
- ; CONTEXT SWITCH
-
-
- ;==============================================================================
- ; DEFINE BIOS DATA SEGMENT OFFSETS
- ;==============================================================================
-
- BiosData segment at 40h
- org 17h
- KbFlag label byte ;current shift status bits
- org 18h
- KbFlag1 label byte ;current key status of toggle keys
- BiosData ends
-
- ;==============================================================================
- ; DEFINE OFFSETS WITHIN BIOS EXTRA DATA SEG
- ;==============================================================================
-
- BiosXX segment at 50h
- org 0
- StatusByte label byte ;PrtSc status
- BiosXX ends
-
- ErrPrtSc equ -1 ;err during last PrtSc
- InPrtSc equ 1 ;PrtSc in progress
-
- ;==============================================================================
- ; DEFINE OFFSETS WITHIN OUR PSP
- ;==============================================================================
-
- Cseg segment byte public
- org 2
- TopSeg label word ;last seg in alloc block
- org 2ch
- EnvSeg label word ;seg of our environment copy
- Cseg ends
-
- ;==============================================================================
- ; DOS COM-FILE ENTRY POINT
- ;==============================================================================
-
- Cseg segment public byte
- assume cs:Cseg, ds:nothing, es:nothing, ss:nothing
- org 100h
-
-
- ComEntry: jmp Init ;JMP to init at bottom of seg
-
-
-
-
- ;==============================================================================
- ; IDENTIFICATION CODES FOR THIS TSR (MUST BE UNIQUE FOR EACH CO-EXISTING TSR)
- ; HIGH BYTE OF GetId MUST NOT MATCH ANY AH REQUEST CODES FOR INT16H.
- ;==============================================================================
-
- GetId equ "bn" ;INT16h AX val to get MyId
- MyId equ "BN" ;ID of this TSR
-
- ;==============================================================================
- ; FLAGS AND PTRS FOR RESIDENT HANDLING
- ;==============================================================================
-
- TsrMode db 0 ;bits for various modes
- InInt08 equ 1 SHL 0 ;timer0 tick handler
- InInt09 equ 1 SHL 1 ;keyboard handler
- InInt13 equ 1 SHL 2 ;BIOS disk I/O
- InInt28 equ 1 SHL 3 ;INT28 handler
- In28Call equ 1 SHL 4 ;we have issued INT28
- InPopup equ 1 SHL 5 ;popup routine activated
- NewDos equ 1 SHL 6 ;DOS 2.x in use
- InDosClr equ 1 SHL 7 ;InDos 0 at popup time
-
- KeyMode db 0 ;bits for hotkey status
- HotIsShift equ 1 SHL 0 ;hotkey is shift state
- InHotMatch equ 1 SHL 1 ;so far keys match hotkey seq
- HotKeyOn equ 1 SHL 2 ;full hotkey pressed
-
- InDosPtr label dword ;seg:off of InDos flag
- InDosOff dw 0
- InDosSeg dw 0
-
- CritErrPtr label dword ;seg:off of CritErr flag
- CritErrOff dw 0
- CritErrSeg dw 0
-
- GetOutFlag dw 0 ;set to cause de-install
-
- ;==============================================================================
- ; DATA FOR INT09H HANDLER TO CHECK FOR HOTKEY COMBINATION
- ;==============================================================================
-
- ; ------------ EQU'S FOR BIT SHIFTS WITHIN KEYBOARD FLAGS
-
- InsState equ 80h
- CapsState equ 40h
- NumState equ 20h
- ScrollState equ 10h
- AltShift equ 08h
- CtlShift equ 04h
- LeftShift equ 02h
- RightShift equ 01h
-
- InsShift equ 80h
- CapsShift equ 40h
- NumShift equ 20h
- ScrollShift equ 10h
- HoldState equ 08h
-
- ; ------------ SCAN CODES FOR VARIOUS SHIFT KEYS
-
- LeftDown equ 42 ;scan code of left shift key
- LeftUp equ LeftDown OR 80h
- RightDown equ 54 ;scan code of right shift key
- RightUp equ RightDown OR 80h
- AltDown equ 56 ;scan code of alt key
- AltUp equ AltDown OR 80h
- CtlDown equ 29 ;scan code of ctrl key
- CtlUp equ CtlDown OR 80h
- ScrollDown equ 70 ;scan code of scroll lock
- ScrollUp equ ScrollDown OR 80h
-
- ; ------------ MISC KEYBOARD DATA
-
- KbData equ 60h ;keyboard data input
-
- ;==============================================================================
- ; TO USE A SHIFT KEY COMBINATION AS HOT KEY:
- ; - SET THE FLAG HotIsShift IN KeyMode
- ; - DEFINE THE SHIFT STATUS BITS IN THE VARIABLE HotKeyShift
- ;
- ; TO USE A SERIES OF SCAN CODES AS HOT KEY:
- ; - CLEAR THE FLAG HotIsShift IN KeyMode
- ; - INSERT THE MAKE AND BREAK SCAN CODES IN THE HotKeySeq STRING
-
- ; NOTE: WITH THIS IMPLEMENTATION YOU SHOULD NOT USE A HOT KEY
- ; SEQUENCE WHICH PRODUCES A KEY IN THE BIOS KEYBOARD QUEUE,
- ; SINCE THE KEY IS NOT REMOVED BEFORE CALLING THE POPUP ROUTINE.
- ;
- ; NOTE: HOTKEY TYPE AND CONTENTS OF HOTKEY VARIABLES MAY BE CHANGED AT RUN TIME
- ;==============================================================================
-
- HotKeyShift db AltShift OR RightShift ;shift state IF HotIsShift=FF
-
- HotKeySeq db AltDown,RightDown
- HotKeyLen equ $-HotKeySeq
-
- HotIndex db 0 ;# key in seq to compare next
- BetweenKeys db 0 ;timeout count between keys
- KeyTimeOut equ 10 ;more ticks means not a hotkey
-
- ;==============================================================================
- ; DATA FOR INT08H HANDLER TO CHECK FOR POPUP
- ;==============================================================================
-
- SafeWait db 0 ;count-down for safe popup
- MaxWait equ 8 ;wait no more 8/18 sec
-
- ;==============================================================================
- ; PROCESS & SYSTEM DATA
- ;==============================================================================
-
- OurSS dw 0 ;stack for popup routine
- OurSP dw 0
- StackSize equ 512 ;bytes to reserve for stack
-
- OldSS dw 0 ;old stack seg
- OldSP dw 0 ;old stack off
-
- OurPSP dw 0 ;our PSP seg
- OldPSP dw 0 ;old PSP seg
-
- OldDTA label dword ;seg:off of old DTA area
- OldDTAOff dw 0
- OldDTASeg dw 0
-
- OurDTA label dword ;seg:off of our DTA
- OurDTAOff dw 0
- OurDTASeg dw 0
-
- OldBreak db 0 ;old ctrl-break state
- OldExtErr dw 3 dup (0) ;AX,BX,CX of ext err
-
- ;==============================================================================
- ; LOCATIONS FOR SAVED INTERRUPT VECTORS
- ;==============================================================================
-
- OldInt08 label dword ;Timer0 loaded before this
- OldInt08Off dw 0
- OldInt08Seg dw 0
-
- OldInt09 label dword ;Kb handler loadde before this
- OldInt09Off dw 0
- OldInt09Seg dw 0
-
- OldInt13 label dword ;BIOS diskette I/O
- OldInt13Off dw 0
- OldInt13Seg dw 0
-
- OldInt16 label dword ;BIOS kb Q-handler
- OldInt16Off dw 0
- OldInt16Seg dw 0
-
- OldInt1B label dword ;^break of process we steal
- OldInt1BOff dw 0
- OldInt1BSeg dw 0
-
- OldInt1C label dword ;timer tick of process we steal
- OldInt1COff dw 0
- OldInt1CSeg dw 0
-
- OldInt21 label dword ;DOS function dispatcher
- OldInt21Off dw 0
- OldInt21Seg dw 0
-
- PrevInt23 label dword ;^C of process we steal
- PrevInt23Off dw 0
- PrevInt23Seg dw 0
-
- OldInt23 label dword ;^C internal handler (IRET)
- OldInt23Off dw 0
- OldInt23Seg dw 0
-
- OldInt24 label dword ;crit err of process we steal
- OldInt24Off dw 0
- OldInt24Seg dw 0
-
- OldInt28 label dword ;DOS idles loaded before this
- OldInt28Off dw 0
- OldInt28Seg dw 0
-
- ApplPSP dw 0 ;stores application PSP
- CurrentAlloc dw 0 ;application memory allocation
-
- ;==============================================================================
- ; SPEAKER/TONE GENERATION DATA
- ;==============================================================================
-
- PB0port equ 61h ;port for speaker bit
- ErrLen1 equ 10 ;# outer err beep cycles
- ErrLen2 equ 80 ;# inner err beep cycles
- ErrLow equ 100 ;low tone wait in err beep
- ErrHi equ 40 ;hi tone wait in err beep
-
- ;==============================================================================
- ; ErrBeep - PRODUCE ERROR-INDICATING SOUND ON SPEAKER
- ;==============================================================================
-
- ErrBeep proc near
- assume ds:nothing, es:nothing, ss:nothing
-
- push ax ;save regs used
- push bx
- push cx
- push dx
-
- mov cx,ErrLen1 ;# mix-cycles for beep
-
- ErrBeep1: mov dx,ErrLow ;wait time for half-cycle
- mov bx,ErrLen2 ;len of one tone
- call DoTone ;output low err tone
- mov dx,ErrHi ;wait time for half-cycle
- mov bx,ErrLen2 ;len of one tone
- call DoTone ;output low err tone
-
- loop ErrBeep1 ;loop for some time
-
- pop dx
- pop cx ;restore regs
- pop bx
- pop ax
- ret
- ErrBeep endp
-
- ;==============================================================================
- ; DoTone - OUTPUT ONE TONE ON THE SPEAKER
- ;
- ; INPUT: DX: LOOP WAIT TIME FOR HALF CYCLE IN TONE
- ; BX: NUMBER OF CYCLES FOR TONE DURATION
- ; OUTPUT: NONE
- ; REGS: ALL PRESERVED
- ;==============================================================================
-
- DoTone proc near
- assume ds:nothing, es:nothing, ss:nothing
-
- push ax ;save regs used
- push bx
- push cx
- in al,PB0port ;get PB0 reg pattern
- mov ah,al ;save it
-
- DoTone1: and al,0fch ;mask off speaker bit
- out PB0port,al ;pull!
- mov cx,dx ;half cycle in counter
- DoTone2: loop DoTone2 ;leave there for half a cycle
- or al,2 ;turn on speaker bit
- out PB0port,al ;push!
- mov cx,dx ;half cycle in counter
- DoTone3: loop DoTone3 ;leave there for half a cycle
-
- dec bx ;count down tone duration
- jnz DoTone1 ;go through full tone
-
- mov al,ah ;AL=original PB0 reg value
- out PB0port,al ;restore
-
- pop cx ;restore regs
- pop bx
- pop ax
- ret
- DoTone endp
-
- ;==============================================================================
- ; TestSafe - CHECK IF THIS IS A SAFE TIME TO DO A POP UP
- ;
- ; RETURN CLC IF SAFE TO POP UP, CY IF NOT SAFE.
- ;
- ; CHECK IF ANY INTs ARE IN CRITICAL AREAS (InInt09 & InInt13)
- ; CHECK IF WE ARE IN AN OUR OWN INT28 CALL (In28Call)
- ; CHECK 8259A PIC ISR REGISTER FOR MISSING EOIs
- ; CHECK IF DOS IS STABLE FOR POP UP
- ; CHECK IF A PRINT SCREEN IS IN PROGRESS
- ;==============================================================================
-
- TestSafe proc near
- assume ds:nothing, es:nothing
-
- push ax ;save regs used
- push bx
- push ds
-
- ; ------------ CHECK INTs TO SEE IF THEY WERE INTERRUPTED AT BAD TIMES
-
- test TsrMode,InInt09 OR InInt13 OR In28Call
- jnz NotSafe ;jump if any INTs are chopped
-
- ; ------------ CHECK THE 8259A PIC ISR REGISTER FOR NON-EOIed HW INTs
-
- mov al,00001011b ;tell 8259A we want the ISR
- out 20h,al ;8259A command reg
- nop
- nop
- nop ;now, ISR should be ready
- in al,20h ;AL=mask of active INTs
- or al,al ;test all (IRQ0 *did* EOI)
- jnz NotSafe ;jump if active INTs
-
- ; ------------ NOW, ENSURE THAT DOS WAS NOT INTERRUPTED
-
- assume ds:nothing
-
- lds bx,InDosPtr ;now, DS:BX=InDos
- mov al,byte ptr [bx] ;get InDos to AL
- lds bx,CritErrPtr ;now, DS:BX=CritErr
- or al,byte ptr [bx] ;both flags zero?
- jz DosSafe ;YES - DOS is really idle
- test TsrMode,InInt28 ;is this an INT28h
- jz NotSafe ;NO - not safe, should be idle
- cmp al,1 ;YES - one InDos entry only?
- ja NotSafe ;NO - jump if more than one
- DosSafe:
-
- ; ------------ CHECK TO SEE IF A PRINT SCREEN IS IN PROGRESS
-
- mov ax,BiosXX
- mov ds,ax ;move DS to BIOS extra data seg
- assume ds:BiosXX
-
- cmp StatusByte,InPrtSc ;print screen in progress?
- je NotSafe ;YES - jump if prtsc
-
- ; ------------ SEEMS TO BE A SAFE TIME FOR POPUP
-
- IsSafe: clc ;CLC=safe to popup
- jmp short ExitSafe ;end this then
-
- ; ------------ APPARENTLY THIS IS JUST NOT THE TIME TO DO A POPUP
-
- NotSafe: stc ;CY=don't popup now
-
- ; ------------ RETURN TO CALLER WITH CARRY SET/CLEAR
-
- ExitSafe: pop ds ;restore regs
- pop bx
- pop ax
- ret
- TestSafe endp
-
- ;==============================================================================
- ; OurInt08 - TSR INT08H HANDLER TO WATCH FOR HOTKEY AND SAFE POPUP TIMES
- ;
- ; CALL OldInt08
- ; CHECK FOR RE-ENTRANCE INTO CRITICAL INT08 CODE
- ; SET InInt08 FLAG
- ; CHECK FOR TIMEOUT BETWEEN KEYS IN HOTKEY SEQUENCE
- ; CHECK IF HOTKEY WAS PRESSED
- ; CHECK IF ALREADY InPopup OR InInt28
- ; CHECK IF SAFE TIME FOR SYSTEM TO POPUP
- ; UPDATE FLAGS AND CALL POPUP IF SAFE
- ; GIVE ERROR BEEP IF POPUP WAS UNSAFE FOR A LONG TIME
- ; RESET InInt08 FLAG
- ; DO IRET
- ;==============================================================================
-
- ; ------------ NEAR JUMP DESTINATION FOR FAST IRET'S
-
- Exit08: iret ;IRET (!)
-
- ; ------------ ACTUAL INT08 ENTRY POINT
-
- OurInt08 proc far
- assume ds:nothing, es:nothing, ss:nothing
-
- pushf ;simulate INT08
- cli ;in case others forgot it
- call OldInt08 ;call TSRs loaded before us
-
- ; ------------ ENSURE NO RECURSION INTO CRITICAL INT08 CODE
-
- sti ;we'll manage INTs
-
- test TsrMode,InInt08 ;already in here somewhere?
- jnz Exit08 ;YES - don't re-enter
- or TsrMode,InInt08 ;tell people we are here
-
- push ax ;need a few regs in this code
-
- ; ------------ COUNT DOWN TIME-OUT BETWEEN KEYS IN HOTKEY SEQUENCE
-
- test KeyMode,InHotMatch ;are we in a key match?
- jz TestHot08 ;NO - don't care then
- dec BetweenKeys ;count down timeout val
- jnz TestHot08 ;jump if no timeout yet
- mov HotIndex,0 ;start match from beginning
- and KeyMode,not InHotMatch ;just so we know it next time
-
- ; ------------ CHECK FOR POSSIBLE POPUP ACTIONS
-
- TestHot08: test KeyMode,HotKeyOn ;has hotkey been pressed?
- jz ExitInt08 ;NO - jump if no fun here
-
- test TsrMode,InInt28 OR InPopup
- jnz ExitInt08 ;jmp if not alr in business
-
- ; ------------ HOTKEY PRESSED, CHECK TO SEE IF IT IS SAFE TO POPUP
-
- cmp SafeWait,0 ;first time we find hotkey?
- ja TestSafe08 ;NO - wait has alr been set
- mov SafeWait,MaxWait ;# ticks to wait at most
-
- TestSafe08: call TestSafe ;now, CY clear if popup is safe
- jc NotSafe08 ;jump if popup is bad idea
-
- ; ------------ SEEMS SAFE TO POPUP AT THIS TIME, SO DO!
-
- xor al,al ;fast zero
- mov SafeWait,al ;don't count any more
- and KeyMode,not HotKeyOn ;clear hotkey status
- or TsrMode,InPopup ;tell'em we enter popup routine
- and TsrMode,not InInt08 ;OK to enter critical INT08
- call InitPopup ;do actual popup
- or TsrMode,InInt08 ;back in INT08 code here
- and TsrMode,not InPopup ;not in popup code any more
- mov SafeWait,al ;in case of hotkey during popup
- and KeyMode,not HotKeyOn ;clear hotkey status
-
- jmp short ExitInt08 ;finally done
-
- ; ------------ UNSAFE POPUP TIME, COUNT DOWN SafeWait
-
- NotSafe08: dec SafeWait ;count down waiter
- jnz ExitInt08 ;jump if still no timeout
-
- ; ------------ NO SAFE TIMES FOUND FOR QUITE SOME TIME, ERROR
-
- and KeyMode,not HotKeyOn ;might as well clear hotkey
- call ErrBeep ;do an error beep
-
- ; ------------ NORMAL INT08H EXIT, RESET InInt08
-
- ExitInt08: pop ax ;restore regs used
- and TsrMode,not InInt08 ;clear that flag
- iret ;straight back
- OurInt08 endp
-
- ;==============================================================================
- ; OurInt09 - TSR INT09H HANDLER TO WATCH FOR HOTKEY
- ;
- ; SAVE SCAN CODE
- ; CALL OldInt09
- ; CHECK FOR RECURSION INTO CRITICAL INT09 CODE
- ; SET InInt09 FLAG
- ; CHECK IF HOTKEY ALREADY SET
- ; DETERMINE HOTKEY TYPE (SHIFT STATE OR KEY SEQENCE)
- ; CHECK SHIFT STATE IF HotIsShift
- ; COMPARE FOR KEY MATCH IF (NOT HotIsShift)
- ; SET HotKeyOn IF HOTKEY PRESSED
- ; RESET InInt09 FLAG
- ; DO IRET
- ;==============================================================================
-
- ; ------------ NEAR JUMP DESTINATION FOR EARLY EXITS
-
- Exit09: pop bx ;restore regs
- pop ax
- iret ;flags restored from stack
-
- ; ------------ ACTUAL INT09 ENTRY POINT
-
- OurInt09 proc far
- assume ds:nothing, es:nothing, ss:nothing
-
- push ax ;save regs used
- push bx
-
- ; ------------ READ SCAN CODE, IN CASE SEQUENCE MATCHING SELECTED
-
- in al,KbData ;Al=key, preserved by BIOS
-
- ; ------------ CALL BIOS TO PERFORM ITS DUTIES
-
- pushf ;simulate INT (CLI alr set)
- cli ;in case others forgot it
- call OldInt09 ;call BIOS/earlier TSRs
-
- ; ------------ ENSURE NO RECURSION INTO CRITICAL INT09 CODE
-
- sti ;we'll manage INTs
-
- test TsrMode,InInt09 ;alr in business?
- jnz Exit09 ;YES - skip test till clear
- or TsrMode,InInt09 ;tell them we arrived here
-
- ; ------------ DETERMINE HOT KEY TYPE SELECTED
-
- test KeyMode,HotKeyOn ;already hotkey there?
- jnz ExitInt09 ;YES - no double hotkeys here
-
- test KeyMode,HotIsShift ;shift state type hotkey?
- jz CompSeq09 ;NO - go compare sequence
-
- ; ------------ COMPARE CURRENT SHIFT STATUS AGAINST HOTKEY
-
- push ds ;save current ds
- mov ax,BiosData ;move DS to BIOS data seg
- mov ds,ax ;DS can now access keyb vars
- assume ds:BiosData ;tell MASM about our DS
- mov al,KbFlag ;get BIOS shift state bits
- pop ds ;restore
- assume ds:nothing ;last thing we know about him
-
- and al,HotKeyShift ;isolate relevant bits
- cmp al,HotKeyShift ;our shift state in effect?
- jne ExitInt09 ;NO - not that shift state
- or KeyMode,HotKeyOn ;YES - flag hotkey
- jmp short ExitInt09 ;now we can be proud to leave
-
- ; ------------ MATCH KEY IN SCAN CODE SEQUENCE
-
- CompSeq09: mov bl,HotIndex ;next scan code to match
- xor bh,bh ;must be word
- cmp al,HotKeySeq[bx] ;does key match?
- je HotMatch09 ;YES - jump if match
- mov HotIndex,bh ;search from start next time
- and KeyMode,not InHotMatch ;current no match
- jmp short ExitInt09 ;now end this
-
- ; ------------ KEY MATCHED...NEXT SCAN CODE IN HotKeySeq
-
- HotMatch09: inc bl ;new code at next pass
- cmp bl,HotKeyLen ;did we match whole sequence?
- jae HotHit09 ;YES - jump if full sequence
- mov HotIndex,bl ;NO - save new count
- mov BetweenKeys,KeyTimeOut ;reset counter between keys
- or KeyMode,InHotMatch ;we are in a match now
- jmp short ExitInt09 ;time to end this
-
- ; ------------ KEY MATCHED ALL SCAN CODES IN HOTKEY SEQUENCE
-
- HotHit09: or KeyMode,HotKeyOn ;say hotkey was pressed
- mov HotIndex,bh ;match 1st code next time
- and KeyMode,not InHotMatch ;that's the end of a match
-
- ; ------------ EXIT FROM INT09H, RESET InInt09 FLAG
-
- ExitInt09: and TsrMode,not InInt09 ;tell'em we left this code
- pop bx ;restore regs
- pop ax
- iret ;flags restored from stack
- OurInt09 endp
-
- ;==============================================================================
- ; OurInt13 - SET InInt13 FLAG TO SAY THAT WE ARE IN AN INT13H
- ;==============================================================================
-
- OurInt13 proc far
- assume ds:nothing, es:nothing, ss:nothing
-
- pushf ;save flags we use
- or TsrMode,InInt13 ;remember we are in BIOS now
- popf ;restore flags
-
- pushf ;simulate INT13
- cli ;just in case others forgot
- call OldInt13 ;let BIOS handle it all
- sti ;turn 'em back on
-
- pushf ;BIOS uses flag return
- and TsrMode, not InInt13 ;tell people we left INT13h
- popf
-
- ret 2 ;throw flags off stack
- OurInt13 endp
-
- ;==============================================================================
- ; OurInt16 - TSR INT16H HANDLER, INT28 CHAIN INTERFACE
- ;
- ; INPUT: AX = GetId
- ; OUTPUT: AX = MyId
- ; REGS: AX LOST, ALL OTHERS PRESERVED
- ; DESCRIPTION: DETERMINE IF TSR WITH THIS ID IS ALREADY IN MEMORY
- ;
- ; INPUT: AH = 00
- ; OUTPUT: AX = NEXT KEY FROM BUFFER
- ; REGS; AX LOST, ALL OTHERS PRESERVED
- ; DESCRIPTION: RETURN A KEY FROM KEYBOARD BUFFER, WAIT TILL KEY IS PRESSED
- ;
- ; INPUT: AH = 02
- ; OUTPUT: AX = KEY FROM BUFFER IN ANY
- ; ZF = NO KEYS IN BUFFER (AX PRESERVED)
- ; NZ = KEY IN BUFFER (RETURNED IN AX, KEY STILL IN BUFFER)
- ; DESCRIPTION: CHECK BUFFER FOR ANY PENDING KEYS, RETURN KEY IF ANY
- ;
- ; NOTE: ALL OTHER AX REQUEST CODES ARE PASSED ON TO BIOS INT16H HANDLER.
- ;
- ; NOTE: DURING INT28 POPUP (InPopup AND NOT InDosClr) FUNCTIONS AH=0 AND
- ; AH=1 WILL ISSUE INT28, UNLESS InDos HAS FROM VALUE AT POPUP OR
- ; CritErr HAS BEEN SET.
- ;==============================================================================
-
- OurInt16 proc far
- assume ds:nothing, es:nothing, ss:nothing
-
- sti ;we'll manage INTs
- pushf ;save callers flags
- cmp ax,GetId ;return ID request?
- jne NotId16 ;NO - jump if not
-
- ; ------------ TSR DIAGNOSTIC REQUEST, RETURN SPECIAL VALUE TO SAY WE ARE HERE
-
- mov ax,MyId ;ID val returned in AX
- popf ;restore flags
- iret ;return to caller
-
- ; ------------ PASS CONTROL TO BIOS, FLAGS ON STACK
-
- GoBios16: popf ;restore flags at INT time
- jmp OldInt16 ;continue in the woods
-
- ; ------------ REGULAR BIOS INT16 REQUEST, CHECK FOR ANY FANCY ACTIONS
-
- NotId16: test TsrMode,InPopup ;are we in a popup?
- jz GoBios16 ;NO - leave rest with BIOS
- test TsrMode,InDosClr ;InDos clear at popup?
- jnz GoBios16 ;YES - no need to signal INT28
-
- popf ;restore original flags
- push bx ;we need a few regs here
- push cx
- push si
- push ds
- pushf ;original flags back on stack
-
- ; ------------ GET REQUEST CODE TO BH ENHANCED BIT TO BL
-
- mov bh,ah ;BH=function request code
- and bh,not 10h ;zap enhanced kybd bit
- cmp bh,1 ;any function above 1?
- ja ExitBios16 ;YES - leave rest with BIOS
-
- mov bl,ah ;BL used for enhanced bit
- and bl,10h ;BL=value of enhanced bit
-
- ; ------------ GET InDos To CL, CritErr to CH, SETUP REGS
-
- assume ds:nothing
-
- lds si,InDosPtr ;DS:[SI]=InDos
- mov cl,byte ptr [si] ;CL=InDos value
- lds si,CritErrPtr ;ES:[SI]=CritErr
- mov ch,byte ptr [si] ;CH=CritErr value
-
- mov si,ax ;save AX call value
-
- mov ax,cs ;move DS here, now we got it
- mov ds,ax
- assume ds:Cseg ;everybody should know
-
- ; ------------ CHECK KEYBOARD BUFFER, ORIGINAL FLAGS ON STACK
-
- Wait16: mov ah,1 ;AH=1=test buffer status
- or ah,bl ;maintain enhanced bit value
-
- popf ;restore original flags
- pushf ;simulate INT
- cli ;in case others forgot
- call OldInt16 ;now, ZF set if no keys
- pushf ;save result flags
- jnz TestSkip16 ;jump if a key was found
-
- ; ------------ NO KEY FOUND, CALL INT28 IF DOS InDos ALLOWS
-
- cmp cx,0001h ;CritErr=0, InDos=1 ?
- jne NextKey16 ;NO - wait for next key
- or TsrMode,In28Call ;tell people we called this INT
- int 28h ;now take your chance
- and TsrMode,not In28Call ;end of that call
-
- ; ------------ TEST BUFFER AGAIN IF INT16.00, IRET IF INT16.01
-
- NextKey16: or bh,bh ;is this a wait for key?
- jz Wait16 ;YES - then go wait for it!
- mov ax,si ;restore original AX contents
- jmp short Exit16 ;NO - exit with status we got
-
- ; ------------ KEY IN BUFFER, IF CTRL-C WE MAY HAVE TO SKIP IT, FLAGS ON STACK
-
- TestSkip16: cmp al,3 ;is this Ctrl-C?
- jne TestExit16 ;NO - determine exit method
- test cx,not 0001h ;anything but InDos=1?
- jz TestExit16 ;NO - determine exit method
-
- ; ------------ SKIP CTRL-C IN KEYBOARD BUFFER
-
- mov ah,bl ;AH=0 + enhanced bit
- popf ;restore original INTs
- pushf ;save again
- pushf ;simulate INT
- cli ;simulate properly!
- call OldInt16 ;now, key should be gone
- jmp short Wait16 ;do as if nothing had happened
-
- ; ------------ KEY IN AX, IRET IF INT16.01, LEAVE WITH BIOS IF INT16.00
-
- TestExit16: or bh,bh ;is this a wait for key?
- jnz Exit16 ;NO - do fast return
- mov ax,si ;YES - restore AX code
-
- ; ------------ PASS CONTROL TO BIOS, FLAGS & REGS ON STACK
-
- assume ds:nothing
-
- ExitBios16: popf ;restore work flags
- pop ds ;restore regs
- pop si
- pop cx
- pop bx
- cli ;should look like an INT
- jmp OldInt16 ;leave rest with BIOS
-
- ; ------------ RETURN FROM INT16, FLAGS & REGS ON STACK
-
- assume ds:nothing
-
- Exit16: popf ;restore proper flags
- pop ds ;restore regs
- pop si
- pop cx
- pop bx
- ret 2 ;IRET, without flags restore
-
- OurInt16 endp
-
- ;==============================================================================
- ; OurInt21 - INT21 FILTER TO THROW DANGEROUS DOS CALLS ON CRITICAL STACK
- ;
- ; CHECK IF InPopup AND InDosClr
- ; CHECK FUNCTION USES CONSOLE STACK
- ; SET CritErr IN DOS IF CONSOLE STACK USED
- ; CALL OldInt21
- ; RESTORE CritErr IF CRITICAL STACK USED
- ;==============================================================================
-
- OurInt21 proc far
- assume ds:nothing, es:nothing
-
- pushf ;save calling flags
- sti
-
- test TsrMode,InPopup ;are we in a popup?
- jz GoDos21 ;NO - don't worry then
- test TsrMode,InDosClr ;console stack idle?
- jnz GoDos21 ;YES - nothing fancy then
-
- ; ------------ THIS IS 2ND CALL INTO DOS, SEE IF USING CONSOLE STACK
-
- cmp ah,0ch ;any function 00-0C?
- jbe UseCrit21 ;YES - use critical stack
- test TsrMode,NewDos ;NO - is this DOS 3.x?
- jnz GoDos21 ;YES - no other to worry about
- cmp ah,50h ;set PSP function?
- je UseCrit21 ;YES - use critical stack
- cmp ah,51h ;get PSP function?
- jne GoDos21 ;NO - leave it with DOS
-
- ; ------------ FORCE USE OF CRITICAL STACK FOR THIS CALL
-
- UseCrit21: assume ds:nothing ;nothing to say about DS
-
- push si ;save regs
- push ds
- lds si,CritErrPtr ;now, DS:[SI]=InDos
- mov byte ptr [si],-1 ;FF=use crit stack now
- pop ds ;restore regs
- pop si
-
- popf ;retsore flags setting
- pushf ;simulate INT
- cli ;in case others forgot
- call OldInt21 ;flags already on stack
-
- push si ;save regs
- push ds
- lds si,CritErrPtr ;now, DS:[SI]=InDos
- mov byte ptr [si],0 ;0=back to default stack
- pop ds ;restore regs
- pop si
-
- ret 2 ;IRET throw old flags
-
- ; ------------ PASS CONTROL TO DOS, FLAGS ON STACK
-
- GoDos21: popf ;restore original flags
- cli ;just in case someone forgot
- jmp OldInt21 ;let DOS handle the rest
- OurInt21 endp
-
- ;==============================================================================
- ; OurInt24 - SAFE DOS CRITICAL ERROR HANDLER
- ;
- ; IF DOS 3.X, FAIL THE SYSTEM CALL
- ; IF NOT DOS 3.X, IGNORE ERROR
- ;==============================================================================
-
- OurInt24 proc far
- assume ds:nothing, es:nothing, ss:nothing
-
- mov al,3 ;AL=3=fail system call
- test TsrMode,NewDos ;are we using DOS 3.x?
- jnz Exit24 ;YES - OK to use AL=3
- xor al,al ;NO - have to ignore err then
- Exit24: iret ;return to DOS
- OurInt24 endp
-
- ;==============================================================================
- ; OurInt28 - TSR INT28H HANDLER, ALLOWS POPUP DURING DOS IDLE CALLS
- ;
- ; CALL OldInt28
- ; CHECK FOR RECURSION INTO CRITICAL INT28 CODE (& OTHER INTs AS WELL)
- ; SET InInt28 FLAG
- ; CHECK FOR HOTKEY
- ; CHECK IF SAFE TO POPUP
- ; DO POPUP IF SAFE AT THIS TIME
- ; RESET InInt28 FLAG
- ; DO IRET
- ;==============================================================================
-
- ; ------------ NEAR JUMP DESTINATION FOR FAST IRET'S
-
- Exit28: iret ;IRET (!)
-
- ; ------------ ACTUAL INT28 ENTRY POINT
-
- OurInt28 proc far
- assume ds:nothing, es:nothing, ss:nothing
-
- pushf
- cli ;in case others forgot it
- call OldInt28 ;call TSRs loaded before this
-
- ; ------------ ENSURE NO RECURSION ON CRITICAL INT28 CODE
-
- sti ;we'll manage INT's after this
- test TsrMode,InInt08 OR InInt28 OR In28Call OR InPopup
- jnz Exit28 ;exit fast if already going
- or TsrMode,InInt28 ;tell'em we are here
-
- ; ------------ CHECK FOR POSSIBLE POPUP ACTIONS
-
- test KeyMode,HotKeyOn ;any hotkeys pressed?
- jz ExitInt28 ;NO - don't check any more then
-
- ; ------------ HOTKEY WAS PRESSED, ENSURE IT'S SAFE TO DO POPUP
-
- call TestSafe ;now, CY clear if popup is OK
- jc ExitInt28 ;jump if not to popup
-
- ; ------------ SEEMS OK TO DO POPUP, SO DO!
-
- and KeyMode,not HotKeyOn ;clear hotkey status
- or TsrMode,InPopup ;tell'em we enter popup routine
- and TsrMode,not InInt28 ;OK to enter critical INT28
- call InitPopup ;then do popup
- or TsrMode,InInt28 ;back in INT28 code here
- and TsrMode,not InPopup ;not in popup code any more
- and KeyMode,not HotKeyOn ;clear hotkeys during popup
-
- ; ------------ NORMAL INT28H EXIT, RESET InInt28 FLAG
-
- ExitInt28: and TsrMode,not InInt28 ;tell'em we left this code
- iret ;we have nothing more to say
- OurInt28 endp
-
- ;==============================================================================
- ; NopInt - DUMMY IRET INSTRUCTION USED BY EMPTY INT HANDLERS
- ;==============================================================================
-
- NopInt: iret ;immediate return
-
-
- ;==============================================================================
- ; DE-INSTALL THIS TSR
- ;
- ; NOTE!
- ; ***this is only supposed to be***
- ; ***invoked at a DOS prompt!!!!***
- ;
- ; - RESTORE INTERRUPT VECTORS
- ; - GIVE BACK THE MEMORY WE STOLE
- ; - DO A NORMAL "4C" RETURN TO DOS
- ;
- ;==============================================================================
-
- DeInstall proc near
- push ds
-
- mov bx,OurPSP ;restore PSP to point
- mov ax,5000h ;to us
- int 21h
-
- pop ds
- push ds
- mov ax, 2528h
- lds dx, OldInt28
- int 21h ;give back dos idle
-
- pop ds
- push ds
- mov ax, 2521h
- lds dx, OldInt21
- int 21h ;give back dos funct call
-
- pop ds
- push ds
- mov ax, 2516h
- lds dx, OldInt16
- int 21h ;give back keyboard int
-
- pop ds
- push ds
- mov ax, 2513h
- lds dx, OldInt13
- int 21h ;give back disk int
-
- pop ds
- push ds
- mov ax, 2509h
- lds dx, OldInt09
- int 21h ;give back kbd handler
-
- pop ds
- push ds
- mov ax, 2508h
- lds dx, OldInt08
- int 21h ;give back timer tick
-
- pop ds
- push ds
- mov ax, 2523h
- lds dx, PrevInt23
- int 21h ;reset ^C handler
-
- pop ds
-
- push es
-
- push cs
- pop es ;free this block
- mov ah, 49h
- int 21h
-
- mov es, EnvSeg
- mov ah, 49h ;free environment block
- int 21h
-
- pop es
- mov ax, 4C00h
- int 21h
-
- DeInstall endp
-
- ;==============================================================================
- ; SCREEN SAVE/RESTORE ROUTINES
- ;==============================================================================
- scrnhold dw 2000 dup (?)
- videoflag dw 0
- videocard dd 0
- savearea dd 0
-
- cursorsave dw 0
- cursortype dw 0
-
-
- fromscr proc near
- push ds ; Save DS
- push es ; and ES
- push bp ; and BP
- mov ax, videoflag
- mov dx,3dah ; Point DX to CGA status port
- les di, savearea ; Dest pointer into ES:DI
- mov cx, 2000 ; Length value into CX
- lds si, videocard ; Source pointer into DS:SI
- cld ; Set string direction to forward
- cmp ax,1 ; mono?
- jne .3 ; no, have to watch for flicker
- rep movsw ; yes, do a fast move
- jmp fromscrexit ;
-
- .3: in al,dx ; Get 6845 status
- rcr al,1 ; Check horizontal retrace
- jb .3 ; Loop if in horizontal retrace: this prevents
- ; starting in mid-retrace, since there is
- ; exactly enough time for 1 and only 1 LODSW
- ; during horizontal retrace
- cli ; No ints during critical section
- .4: in al,dx ; Get 6845 status
- rcr al,1 ; Check for horizontal retrace: LODSW is 1
- ; clock cycle slower than STOSW; because of
- ; this, the vertical retrace trick can't be
- ; used because it causes flicker! (RCR AL,1
- ; is 1 cycle faster than AND AL,AH)
- jnb .4 ; Loop if not in retrace
- lodsw ; Load the video word
- sti ; Allow interrupts
- stosw ; Store the video word
- loop .3 ; Go do next word
- fromscrexit:
- pop bp ; Restore BP
- pop es ; and ES
- pop ds ; and DS
-
- mov ah, 3
- mov bh, 0
- int 10h
- mov cursorsave, dx
- mov cursortype, cx
-
- ret
- fromscr endp
-
-
-
- toscr proc near
- push ds ; Save DS
- push es ; and ES
- push bp ; and BP
- mov ax, videoflag
- mov dx,3dah ; Point DX to CGA status port
- les di, videocard ; Dest pointer into ES:DI
- mov cx,2000 ; Length value (words) into CX
- lds si, savearea ; Source pointer into DS:SI
- cld ; Set string direction to forward
- cmp ax,1 ; mono?
- jne .0 ; no, do flicker trick
- rep movsw ; yes, do it fast
- jmp toscrexit
-
- .0: lodsw ; Grab a video word
- mov bp,ax ; Save it in BP
- mov ah,9 ; Move horiz. + vertical retrace mask
- .1: in al,dx ; Get 6845 status
- rcr al,1 ; Check horizontal retrace
- jb .1 ; Loop if in horizontal retrace: this prevents
- ; starting in mid-retrace, since there is
- ; exactly enough time for 1 and only 1 STOSW
- ; during horizontal retrace
- cli ; No ints during critical section
- .2: in al,dx ; Get 6845 status
- and al,ah ; Check for both kinds of retrace: IF the
- ; video board does not report horizontal
- ; retrace while in vertical retrace, this
- ; will allow several characters to be
- ; stuffed in during vertical retrace
- jz .2 ;
- mov ax,bp ; Get the video word
- stosw ; Store the video word
- sti ; Allow interrupts
- loop .0 ; Go do next word
-
- toscrexit:
- pop bp ; Restore BP
- pop es ; and ES
- pop ds ; and DS
-
- mov dx, cs:cursorsave
- mov ah, 2
- mov bh, 0
- int 10h
- mov cx, cs:cursortype
- mov ah, 1
- int 10h
-
- ret
- toscr endp
-
- ;==============================================================================
- ; CLS---CLEAR THE SCREEN
- ;==============================================================================
-
-
- CLS proc near ; do a BIOS screen clear
- push ax
- push bx
- push cx
- push dx
- push bp
- mov ax, 0600h
- mov cx, 0
- mov dx, 184Fh
- mov bh, 07h
- int 10h
- pop bp
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- CLS endp
-
-
- ;==============================================================================
- ; GOTOXY---PUT THE CURSOR SOMEWHERE
- ;==============================================================================
-
- Gotoxy proc near ; row, column is already in DH, DL
- push ax
- push bx
- mov ah, 2
- mov bh, 0
- int 10h
- pop bx
- pop ax
- ret
- Gotoxy endp
-
- ; --------------------------------------
- ; CURSORON---MAKES THE CURSOR VISIBLE.
- ; --------------------------------------
-
- CursorOn proc near
- mov cx, 0708h
- push cx
- mov ah, 0Fh
- int 10h
- pop cx
- cmp al, 7
- je COmono
- COsetit:
- mov ah, 1
- int 10h
- ret
- COmono:
- mov cx, 0D0Eh
- jmp COsetit
- CursorOn endp
-
-
-
- ;==============================================================================
- ; InitPopup - PREPARES SYSTEM FOR POPUP, THEN CALLS Popup, THEN RESTORES
- ;
- ; ESTABLISH INTERNAL WORK STACK
- ; SAVE CPU REGS
- ; UPDATE InDosClr FLAG WITH CURRENT VALUE OF InDos
- ; SAVE PROCESS RELATED SYSTEM INFO
- ; SAVE USER INTERRUPT VECTORS
- ; INSERT SAFE USER INTERRUPT VECTORS
- ; SAVE CURRENT SCREEN
- ; CALL POPUP ROUTINE
- ; RESTORE SCREEN
- ; RESTORE USER INTERRUPT VECTORS
- ; RESTORE PROCESS AND SYSTEM INFO
- ; CLEAR InDosClr FLAG TO PREVENT UNSAFE INT28 CALLs
- ; SEE IF DE-INSTALL SHOULD BE DONE (GetOutFlag==1)
- ; RESTORE CPU REGS
- ;==============================================================================
-
- InitPopup proc near
- assume ds:nothing, es:nothing, ss:nothing
-
- ; ------------ SWITCH TO PSP INTERNAL STACK
-
- mov OldSS,ss ;save current stack frame
- mov OldSP,sp
-
- cli ;always CLI for the old chips
- mov ss,OurSS ;move SS here
- mov sp,OurSP ;move SP into position
- sti ;OK guys
-
- ; ------------ SAVE ALL REGS
-
- push ax
- push bx
- push cx
- push dx
- push bp
- push si
- push di
- push ds
- push es
-
- mov ax,cs
- mov ds,ax ;mov DS here
- assume ds:Cseg ;tell MASM that
-
- ; ------------ TAG VALUE OF InDos FLAG AT TIME OF POPUP
-
- or TsrMode,InDosClr ;assume InDos=0
- les si,InDosPtr ;now, ES:[SI]=InDos
- cmp byte ptr es:[si],1 ;InDos set? (>2 impossible)
- jb InDosSaved ;NO - jump if all clear DOS
- and TsrMode,not InDosClr ;clear flag for popup InDos
- InDosSaved:
-
- ; ------------ SAVE DOS 3.X EXTENDED ERROR INFO
-
- test TsrMode,NewDos ;really DOS 3.x?
- jz Dos3Saved ;NO - jump if not 3.x
-
- mov ah,59h ;to get err info from DOS
- xor bx,bx ;BX must be zero
- push ds ;save DS (killed by DOS)
- int 21h ;ext err info in AX,BX,CX
- pop ds ;restore
- mov OldExtErr[0],ax ;save
- mov OldExtErr[2],bx
- mov OldExtErr[4],cx
-
- Dos3Saved:
-
- ; ------------ SAVE CURRENT BREAK STATE, RELAX BREAK CHECKING
-
- mov ax,3302h ;to swap DL with BREAK value
- xor dl,dl ;DL=0=relax checking
- int 21h ;current level in DL
- mov OldBreak,dl ;save current level
-
- ; ------------ SAVE CURRENT USER INT VECTORS
-
- mov ax,351bh ;BIOS ctrl-break int
- int 21h ;ES:BX=vector
- mov OldInt1BOff,bx ;save it
- mov OldInt1BSeg,es
-
- mov ax,351ch ;BIOS timer tick
- int 21h ;ES:BX=vector
- mov OldInt1COff,bx ;save it
- mov OldInt1CSeg,es
-
- mov ax,3523h ;DOS ctrl-C
- int 21h ;ES:BX=vector
- mov OldInt23Off,bx ;save it
- mov OldInt23Seg,es
-
- mov ax,3524h ;DOS crit err handler
- int 21h ;ES:BX=vector
- mov OldInt24Off,bx ;save it
- mov OldInt24Seg,es
-
- ; ------------ INSERT DUMMY IRET INTO DANGEROUS VECTORS
-
- mov dx,offset NopInt ;now, DS:DX=dunny iret
- mov ax,251bh ;BIOS ctrlk-break handler
- int 21h ;set to IRET
- mov ax,251ch ;BIOS timer tick
- int 21h ;set to IRET
- mov ax,2523h ;DOS ctrl-C handler
- int 21h ;set to IRET
-
- ; ------------ ESTABLISH SAFE CRITICAL ERROR HANDLER
-
- mov dx,offset OurInt24 ;now, DS:DX=safe crit err
- mov ax,2524h ;to set crit err handler
- int 21h
-
- ; ------------ SAVE CURRENT DTA AREA, SET OUR DEFAULT DTA
-
- mov ah,2fh ;to obtain current DTA from DOS
- int 21h ;DTA addr now in ES:BX
- mov OldDTAOff,bx ;save it
- mov OldDTASeg,es
-
- push ds ;save DS for a while
- lds dx,OurDTA ;DS:DX=our DTA addr
- mov ah,1ah ;to set DTA via DOS
- int 21h ;set that addr
- pop ds ;restore DS
-
- ; ------------ SAVE CURRENT PSP, ESTABLISH OURS INSTEAD
-
- mov ax,5100h ;to get PSP from DOS
- int 21h ;current PSP now in BX
- mov OldPSP,bx ;save it
- mov bx,OurPSP ;het our PSP instead
- mov ax,5000h ;to set our PSP
- int 21h
-
- ; ------------ CALL USER POPUP ROUTINE
-
- call FromScr ;save screen
- call Popup ;finally!
- call ToScr ;put screen back
-
- ; ------------ RESTORE TO SAVED CURRENT PROCESS
-
- mov bx,OldPSP ;new current process in BX
- mov ax,5000h ;to set PSP via DOS
- int 21h ;restore original PSP
-
- ; ------------ RESTORE SAVED DTA
-
- push ds ;save DS for a while
- lds dx,OldDTA ;DS:DX=our DTA addr
- mov ah,1ah ;to set DTA via DOS
- int 21h ;set that addr
- pop ds ;restore DS
-
- ; ------------ RESTORE SAVED INTERRUPT VECTORS
-
- push ds ;save for a while
- assume ds:nothing ;be careful about MASM
-
- lds dx,OldInt1B ;BIOS ctrl-break handler
- mov ax,251bh
- int 21h
-
- lds dx,OldInt1C ;BIOS timer tick
- mov ax,251ch
- int 21h
-
- lds dx,OldInt23 ;ctrl-C handler (an IRET)
- mov ax,2523h
- int 21h
-
- lds dx,OldInt24 ;DOS crit err handler
- mov ax,2524h
- int 21h
-
- pop ds ;restore data seg DS
- assume ds:Cseg
-
- ; ------------ RESTORE SAVED BREAK CHECKING LEVEL
-
- mov ax,3301h ;to set break check level
- mov dl,OldBreak ;get saved break state
- int 21h
-
- ; ------------ RESTORE DOS 3.X SPECIFIC SYSTEM INFO
-
- test TsrMode,NewDos ;using DOS 3.x
- jz Dos3Restored ;NO - jump if old DOS 2
- mov dx,offset OldExtErr ;DS:DX=3 words of ext err
- mov ax,5d0ah ;to set ext err info
- int 21h
- Dos3Restored:
-
- ; ------------ RESET InDosSet FLAG VALUE TO PREVENT UNSAFE INT28
-
- or TsrMode,InDosClr ;now we only care that InDos=0
-
- ; ------------ DO WE WANT TO DE-INSTALL?
-
- cmp GetOutFlag, 0 ;set in POPUP if user said
- je RestoreTheRegs ;to remove ourselves
-
- jmp DeInstall ;go die gracefully
-
- ; ------------ RESTORE USER REGS
-
- RestoreTheRegs:
- pop es
- pop ds
- pop di
- pop si
- pop bp
- pop dx
- pop cx
- pop bx
- pop ax
- assume ds:nothing
-
- ; ------------ RETURN TO USER STACK
-
- cli ;always CLI for the old chips
- mov ss,OldSS ;restore SS
- mov sp,OldSP ;restore SP
- sti ;OK guys
-
- ret
- InitPopup endp
-
- ;==============================================================================
- ; Popup - POPUP USER ROUTINE
- ;
- ; ALL REGISTERS EXCEPT SS:SP AND DS MAY BE CHANGED.
- ; DS IS PRESET TO THE TSR DATA SEGMENT.
- ;
- ; NOTE: UPON ENTRY TO THIS ROUTINE ALL DOS FUNCTIONS MAY BE CALLED.
- ; IF POPUP WAS DONE ON INT28, WITH CritErr-1, ALL DOS FUNCTIONS
- ; THAT WOULD NORMALLY USE THE CONSOLE STACK, WILL GO TO THE CRITICAL
- ; STACK, HENCE PREVENTING FURTHER POPUP DURING THE DOS CALL.
- ; (HOWEVER, MOST TSRs WOULD NOT POPUP ANYWAY, SINCE InDos-2).
- ;
- ; ADDRESSES OF THE InDos AND CritErr ARE STORED IN THE DOUBLE WORDS
- ; InDosPtr AND CritErrPtr.
- ;
- ; AT ENTRY CritErr FLAG IS 0 (ZERO), InDos NO GREATER THAN 1 (ONE).
- ;
- ; THE SCREEN HAS ALREADY BEEN SAVED (BUT NOT CLEARED).
- ; IT WILL BE RESTORED AUTOMATICALLY UPON EXIT.
- ;
- ;==============================================================================
-
- ImageHandle dw 0
- ImageName db "C:\Memory.Img", 0 ;in root directory
-
- NamePrompt db 13, 10
- db "Enter name of program to execute: "
- NamePromptLen equ $-NamePrompt
-
- WaitMsg1 db 13, 10, 13, 10
- db "Swapping out...."
- WaitMsgLen1 equ $-WaitMsg1
-
- KeyWaitMsg db 13, 10
- db "Press a key to continue."
- KeyWaitMsgLen equ $-KeyWaitMsg
-
- WaitMsg2 db 13, 10, 13, 10
- db "Swapping in...."
- WaitMsgLen2 equ $-WaitMsg2
-
- CRLFMsg db 13, 10
- CRLFMsgLen equ $-CRLFMsg
-
- PrevSS dw 0
- PrevSP dw 0
- PrevDS dw 0
- PrevES dw 0
- Partition dw 0
-
- CmdLin db 80 dup(0)
-
-
- Popup proc near
- assume ds:Cseg, es:nothing, ss:nothing
-
- ; ------------ IF NO PROGRAM IS ACTIVE, DON'T SAVE 192K
- CheckCurrPgm:
- mov ax, cs ;point to our MCB
- dec ax ;(is 16 bytes below PSP)
- mov es, ax ;'Z' means last one
- CheckThisMCB:
- cmp Byte Ptr es:[0000], "Z" ;MCB signature byte
- je DoLastMCB ;this is last in chain
- cmp Byte Ptr es:[0000], "M" ;'M' is other possibility
- je GotoNextMCB ;try the next one
-
- jmp PopExit ;MCB's are corrupted.
-
- GotoNextMCB:
- add ax, es:[0003] ;length of this block
- inc ax ;plus 1
- mov es, ax ;points to next MCB
- jmp CheckThisMCB
-
- DoLastMCB:
- mov ax, Word Ptr es:[0003] ;get the length
- cmp ax, 12288 ;is it size we need? (paras)
- ja DoThisBlock ;yep.
-
- jmp PopExit ;nope; don't get fancy
-
- DoThisBlock:
- mov ApplPSP, 0 ;default to "it's free"
- mov bx, Word Ptr es:[0001] ;get owner of block
- cmp bx, 0 ;is it a free block?
- jne SetupForSwap ;no, have to swap it out
-
- jmp ExecIt ;free block (don't swap)
-
- SetupForSwap:
- mov ax, es
- inc ax ;point up to PSP
- mov ApplPSP, ax
-
- ; ------------ IF COMMAND.COM OWNS THAT BLOCK, FORGET IT.
-
- mov ax, cs ;point to us
- cmp ax, bx ;owner of block we want
- jbe SwapMemory ;it's okay to use Command
-
- call ErrBeep ;oh-oh, we can't do anything
- jmp PopExit
-
- ; ------------ SAVE 192K OF UPPER MEMORY IN FILE "MEMORY.IMG"
- SwapMemory:
- call CLS
-
- mov cx, 80
- mov di, offset CmdLin
- mov al, 0
- rep stosb
-
- mov ah, 40h
- mov bx, 1
- mov cx, NamePromptLen
- mov dx, offset NamePrompt
- int 21h
-
- call CursorOn
-
- mov ah, 3Fh
- mov bx, 0
- mov cx, 80
- mov dx, offset CmdLin
- inc dx
- int 21h
- mov CmdLin, al
-
- mov si, offset CmdLin
- add si, ax
- mov Byte Ptr [si], 0
-
- mov ah, 40h
- mov bx, 1
- mov cx, WaitMsgLen1
- mov dx, offset WaitMsg1
- int 21h
-
- ; ------------ FIGURE OUT HOW MUCH MEMORY THERE IS; SWAP TOP 192K
-
- int 12h ;should return ax=640
- sub ax, 192 ;subtract what we need
- mov cx, 6 ;shift left 6 bits in order
- shl ax, cl ;to get it in paragraphs
- mov Partition, ax ;remember para addr for later
-
- mov ah, 3Ch
- mov dx, offset ImageName
- mov cx, 0
- int 21h ;create memory image file
- jnc SaveTheHndl
-
- call ErrBeep ;Error!
- jmp PopExit ;unable to create file
-
- SaveTheHndl:
- mov ImageHandle, ax ;we'll need it later
- Write192K:
- mov PrevDS, ds ;we fool with ds quite a bit...
- mov bx, ax ;we also need handle now
- mov ah, 40h
- mov cx, 0FFF0h ;unsigned 65520 quantity
- mov dx, 0
- mov ds, cs:Partition ;recall para addr from above
- int 21h ;write 64K to disk (well, almost)
- jc Error192 ;if I/O error...
- cmp ax, cx ;disk full?
- jne Error192
-
- mov ax, ds
- add ax, 4095 ;bump up to next segment
- mov ds, ax
- mov ah, 40h
- int 21h ;write next 64K (little less, really)
- jc Error192 ;if I/O error...
- cmp ax, cx ;disk full?
- jne Error192
-
- mov ax, ds
- add ax, 4095 ;final segment
- mov ds, ax
- mov ah, 40h
- int 21h ;write last 64K segment
- jc Error192 ;if I/O error...
- cmp ax, cx ;disk full?
- jne Error192
-
- mov ah, 3Eh
- int 21h ;now close it (196,560 bytes written)
-
- mov ax, cs:PrevDS ;restore our ds
- mov ds, ax
-
- jmp FreeIt
-
- Error192:
- call ErrBeep ;do it twice here for id
- call ErrBeep
- mov ah, 3Eh ;close it and get out
- int 21h
- mov ds, cs:PrevDS ;who knows where it wound up??
- jmp PopExit
-
-
- ; ------------ FREE THAT MEMORY SPACE
- FreeIt:
- push es
- mov ax, 0
- mov es, ax
- mov Byte Ptr es:[050Fh], 0
- pop es
-
- mov bx, ApplPSP ;pretend we're in Appl.
- mov ax,5000h ;to set PSP via DOS
- int 21h ;set Application PSP
-
- mov ax, ApplPSP
- dec ax
- mov es, ax ;look at memory control block
- mov bx, word ptr es:[3] ;get current allocation
- mov CurrentAlloc, bx ;and save it
- sub bx, 12160 ;190K = 12160 paragraphs
- mov es, ApplPSP ;block to be shrunk
- mov ah, 4Ah ;setblock
- int 21h ;we now have some free memory
- jnc ExecIt
-
- mov bx,OurPSP ;our current process in BX
- mov ax,5000h ;to set PSP via DOS
- int 21h ;restore our PSP
-
- call ErrBeep ;memory request failed
- call ErrBeep ;do twice
- jmp PopExit ;let's get out of here
-
- ; ------------ RUN PROGRAM
- ExecIt:
- push ds
- pop es
-
- call CLS
-
- mov bx,OurPSP ;our current process in BX
- mov ax,5000h ;to set PSP via DOS
- int 21h ;restore our PSP
-
- mov cs:PrevES, es
- mov cs:PrevDS, ds
- mov cs:PrevSS, ss
- mov cs:PrevSP, sp
-
- mov si, offset CmdLin
- Int 2Eh
-
- CLI
- mov ss, cs:PrevSS
- mov sp, cs:PrevSP
- mov ds, cs:PrevDS
- mov es, cs:PrevES
- STI
-
- ; ------------ GRAB THE MEMORY BACK (BY ALLOCATING ALL OF IT AGAIN)
- ResetMemory:
- cmp ApplPSP, 0 ;is application alive?
- jne GetMain ;yes, re-alloc the memory
-
- jmp PopExit ;no, no need to re-alloc
-
- GetMain:
- mov bx,ApplPSP ;pretend we're the appl.
- mov ax,5000h ;to set PSP via DOS
- int 21h ;restore our PSP
-
- mov es, ApplPSP ;point to Appl's PSP
- mov bx, CurrentAlloc ;what it used to have
- mov ah, 4Ah ;ask for old amt. back
- int 21h ;will DOS do it?
- jnc RestoreImage ;yep, no error
-
- call ErrBeep ;realloc-memory failed
- call ErrBeep ;thrice
- call ErrBeep ;and fall through restore
-
- ; ------------ RESTORE THE 192K MEMORY IMAGE FROM DISK
- RestoreImage:
- push ds
- pop es
-
- mov ah, 40h
- mov dx, offset KeyWaitMsg
- mov cx, KeyWaitMsgLen
- mov bx, 1
- int 21h
-
- mov ax, 0
- int 16h
-
- mov ah, 40h
- mov dx, offset WaitMsg2
- mov cx, WaitMsgLen2
- mov bx, 1
- int 21h
-
- mov bx,OurPSP ;our current process in BX
- mov ax,5000h ;to set PSP via DOS
- int 21h ;restore our PSP
-
- mov ax, 3D00h ;"compatibility mode" open
- mov dx, offset ImageName
- int 21h
- jnc Read192K
-
- call ErrBeep ;a "whoops!"
- jmp PopExit
-
- Read192K:
- mov ImageHandle, ax ;it may have changed
- mov bx, ax
- mov PrevDS, ds ;so we can mess with it
- mov ah, 3Fh ;read back the image
- mov ds, cs:Partition ;point to upper 192K
- mov dx, 0
- mov cx, 0FFF0h ;same segment size as before
- int 21h ;read it
- jc Error192r ;if I/O error...
- cmp ax, cx ;not all bytes read?
- jne Error192r
-
- mov ax, ds
- add ax, 4095 ;bump up to next segment
- mov ds, ax
- mov ah, 3Fh ;here we go again
- int 21h
- jc Error192r ;if I/O error...
- cmp ax, cx ;not all bytes?
- jne Error192r
-
- mov ax, ds
- add ax, 4095 ;bump up to last segment
- mov ds, ax
- mov ah, 3Fh ;for the last time
- int 21h
- jc Error192r ;if I/O error...
- cmp ax, cx ;everything there?
- jne Error192r
-
- mov ah, 3Eh ;close it
- int 21h
- mov ds, cs:PrevDS ;set it back
-
- jmp PopExit ;all done!
-
- Error192r:
- call ErrBeep ;3 times for id
- call ErrBeep
- call ErrBeep
- mov ah, 3Eh ;close error file
- int 21h ;restore ds
- mov ds, cs:PrevDS ;and fall through to exit
-
- ; ------------ RETURN TO THE ORIGINAL APPLICATION
- PopExit:
- push ds
- pop es
- ret
-
- ; ------------ UNINSTALL DOESN'T APPLY HERE
-
- UnInstall:
- mov GetOutFlag, 1 ;will do it later
- ret
- Popup endp
-
- ;==============================================================================
- ; TSR IRON CURTAIN
- ;==============================================================================
-
- TsrCurtain:
-
-
- ;***********************************************************
-
-
-
- ;==============================================================================
- ; NON-RESIDENT MESSAGES FOR INIT
- ;==============================================================================
-
- SecondMsg label byte
- db 7,13,10
- db "The Context Switch program is already loaded!",13,10
- db "$"
-
- HotKeyMsg label byte
- db 13,10,13,10
- db "CONTEXT SWITCH"
- db 13,10
- db "Hit <Alt Right-Shift> to invoke Context Switch."
- db 13,10,13,10
- db "$"
-
- Dos1Msg label byte
- db 7,13,10
- db "Must use DOS release 2.00 or later.",13,10,10
- db "$"
-
- BadDosMsg label byte
- db 7,13,10
- db "Did not recognize DOS version.",13,10,10
- db "$"
-
- ; ------------ DOS ERROR LEVEL EXIT CODES
-
- xOk equ 0 ;normal, OK exit
- xSecond equ 1 ;TSR already loaded
- xBadDos equ 2 ;CritErr flag not found
-
- ;==============================================================================
- ; DISPLAY BANNER, INITIALIZE SYSTEM DATA, CHECK IF ALREADY LOADED,
- ; HOOK INTO INTERRUPT CHAIN, TERMINATE, BUT STAY RESIDENT.
- ;==============================================================================
-
- Init proc near
- assume ds:Cseg, es:nothing, ss:nothing
-
- call CLS
- mov dx,0
- call Gotoxy
-
- ; ------------ USE INT16H DIAGNOSTIC TO SEE IF TSR ALREADY INSTALLED
-
- mov ax,GetId ;INT16h diagnostic request
- int 16h ;now, AX=MyId if installed
- cmp ax,MyId ;TSR already installed?
- jne CheckDos ;NO - jump if not installed
-
- ; ------------ TSR ALREADY INSTALLED, DISPLAY MSG, EXIT
-
- mov dx,offset SecondMsg
- mov ah,9
- int 21h ;display already-installed
- mov dx,offset HotKeyMsg
- mov ah,9
- int 21h ;be kind & disp hot key
- mov ax,4c00h + xSecond ;error level in AL
- int 21h ;abort now
-
- ; ------------ It's only DOS 1! Too bad.
-
- Dos1: mov dx,offset Dos1Msg
- mov ah,9
- int 21h ;display msg about DOS 1
- int 20h ;no err level for DOS 1
-
- ; ------------ ENSURE DOS VERSION IS NEWER THAN 2.00
-
- CheckDos: or TsrMode,NewDos ;assume suing DOS 3.x
- mov ah,30h ;to get DOS version number
- int 21h ;version is AL.AH
- cmp al,2 ;release 2 or newer?
- jb Dos1 ;NO - jump if DOS 1 in use
- ja DosFlags ;jump if DOS 3.x
- and TsrMode,not NewDos ;now, say we use DOS 2.x
-
- ; ------------ INITIALIZE PTRS TO DOS FLAGS - 1ST InDos
-
- DosFlags: mov ax,3400h ;to get InDos ptr
- int 21h ;ES:BX=seg:off of InDos
- mov InDosOff,bx ;save ptr
- mov InDosSeg,es
-
- ; ------------ WE NEED CritErr TO USE PSP FUNCTIONS IN DOS 2.X
-
- xor dl,dl ;DL=0=this is 1st scan
- mov CritErrSeg,es ;DOS seg still in ES
- CritScan: mov di,bx ;start search at InDos
- mov cx,2000h ;search max 1000h words
- mov ax,3e80h ;opcode CMP BYTE PTR [CritErr]
- cld ;better serach forward
-
- CritScan2: repne scasw ;search till found or end
- jne NoCritFound ;jump if CMP not found
- ;ES:[DI-2] at:
- ; CMP BYTE PTR [CritErr]
- ; JNZ ...
- ; MOV SP,stack addr
- cmp byte ptr es:[di][5],0bch ;really CMP SP there?
- jne CritScan2 ;NO - scan again if not
- mov ax,word ptr es:[di] ;now, AX=CritErr offset
- mov CritErrOff,ax ;save it
- jmp short InitData ;OK to end this now
-
- NoCritFound: or dl,dl ;was this1 st scan?
- jnz BadDos ;NO - CritErr not founbd at all
- inc dl ;DL=1=this is 2nd scan
- inc bx ;try scan at odd/even offset
- jmp CritScan ;scan again
-
- ; ------------ COULD NOT LOCATE DOS CritErr FLAG - THAT'S AN ERROR
-
- BadDos: mov dx,offset BadDosMsg
- mov ah,9
- int 21h ;display msg about that
- mov ax,4c00h + xBadDos ;err level in AL
- int 21h ;OK to use 4C (DOS >= 2)
-
- ; ------------ INITIALIZE SYSTEM DATA VARIABLES
-
- InitData: ;store position for stack
- mov OurSP,TsrCurtain - ComEntry + 100h + StackSize
- mov OurSS,cs ;stack seg is code seg
-
- mov ax,5100h ;to get current PSP from DOS
- int 21h ;PSP now in BX
- mov OurPSP,bx ;save our PSP
-
- mov ah,2fh ;to get current DTA from DOS
- int 21h ;now, ES:BX=current DTA
- mov OurDTAOff,bx ;save it
- mov OurDTASeg,es
-
- and KeyMode,not HotIsShift ;hotkey is not shift state
- or TsrMode,InDosClr ;will prevent unsafe INT28s
-
- ; ------------ SAVE VECTORS FOR OUR MONITOR INTERRUPTS
-
- mov ax,3508h ;BIOS timer0 tick handler
- int 21h ;ES:BX=vector
- mov OldInt08Off,bx
- mov OldInt08Seg,es
-
- mov ax,3509h ;BIOS kb HW handler
- int 21h ;ES:BX=vector
- mov OldInt09Off,bx
- mov OldInt09Seg,es
-
- mov ax,3513h ;BIOS disk I/O service
- int 21h ;ES:BX=vector
- mov OldInt13Off,bx
- mov OldInt13Seg,es
-
- mov ax,3516h ;BIOS kb read
- int 21h ;ES:BX=vector
- mov OldInt16Off,bx
- mov OldInt16Seg,es
-
- mov ax,3521h ;DOS functions dispatcher
- int 21h ;ES:BX=vector
- mov OldInt21Off,bx
- mov OldInt21Seg,es
-
- mov ax,3528h ;DOS idle hook
- int 21h ;ES:BX=vector
- mov OldInt28Off,bx
- mov OldInt28Seg,es
-
- mov ax,3523h ;Previous ^C handler
- int 21h ;ES:BX=vector
- mov PrevInt23Off,bx
- mov PrevInt23Seg,es
-
-
- ; ------------ ESTABLISH IRET INT23 TO PREVENT BREAK DURING VECTOR FIX
-
- mov dx,offset NopInt ;DS:DX=dummy vector to set
- mov ax,2523h ;to set ^C handler through DOS
- int 21h ;now, no break will occur
-
- ; ------------ SAVE VECTORS FOR OUR MONITOR INTERRUPTS
-
- mov ax,2508h ;to set our INT08h handler
- mov dx,offset OurInt08 ;DS:DX=new vector
- int 21h ;let DOS set vector
-
- mov ax,2509h ;to set our INT09h handler
- mov dx,offset OurInt09 ;DS:DX=new vector
- int 21h ;let DOS set vector
-
- mov ax,2513h ;to set our INT13h handler
- mov dx,offset OurInt13 ;DS:DX=new vector
- int 21h ;let DOS set vector
-
- mov ax,2516h ;to set our INT16h handler
- mov dx,offset OurInt16 ;DS:DX=new vector
- int 21h ;let DOS set vector
-
- mov ax,2521h ;to set our INT21h handler
- mov dx,offset OurInt21 ;DS:DX=new vector
- int 21h ;let DOS set vector
-
- mov ax,2528h ;to set our INT28h handler
- mov dx,offset OurInt28 ;DS:DX=new vector
- int 21h ;let DOS set vector
-
- mov word ptr savearea+2, ds ;seg of scrnhold
- mov ax, offset scrnhold ;ofs of scrnhold
- mov word ptr savearea, ax ;for scrn-save
-
- mov ah, 15
- int 10h ;get current video mode
-
- cmp al, 7 ;if BW, then we need
- jne IsColor
- mov word ptr videocard + 2, 0B000h ;to set video address
- mov word ptr videocard, 0 ;to B000:0000
- mov videoflag, 1 ;and remember mode
- jmp SayHello
- IsColor:
- mov word ptr videocard + 2, 0B800h ;if color mode, then
- mov word ptr videocard, 0 ;address is B800:0000
- mov videoflag, 0 ;remember we're in color
-
- ; ------------ DISLAY MSG ABOUT HOW WELL THIS IS ALL RUNNING
- SayHello:
- mov dx,offset HotKeyMsg
- mov ah,9
- int 21h ;disp hot key msg.
-
- mov dx,(TsrCurtain-ComEntry+100h+StackSize+15) SHR 4
- mov ax,3100h + xOk ;TSR, AL=err level
- int 21h
- Init endp
-
- ;==============================================================================
-
- Cseg ends
- end ComEntry
-
-
- ===============================================================
-
- Cseg ends
- end ComEntry
-
-