home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
msdos
/
asmutl
/
tsrdemo2.arc
/
TSRDEMO2.ASM
next >
Wrap
Assembly Source File
|
1987-03-10
|
46KB
|
1,503 lines
page 60,132
;==============================================================================
; TSRDEMO2.ASM
; Thomas Brandenborg
; 87.02.11
;
; Sample demonstration of a safe approach for writing TSR programmes.
;
;------------------------------------------------------------------------------
; Copyright 1987 by Thomas Brandenborg. All Rights Reserved
; Written for uploading to Compuserve Forums by
;
; Thomas Brandenborg
; Lundbyesgade 11
; DK-8000 Aarhus C
; DENMARK
;
; This code is intended as a reference to users on Compuserve Forums
; on how to write Terminate-And-Stay resident programmes for Personal
; Cumputers running under DOS versions 2.00 and newer.
;
; The code is not part of any proprietary product, but is rather a
; demonstration of such techniques that may be used to write safe TSR
; programmes.
;
; All or part of it may, however, be used in other software products
; or otherwise distributed assuming the copyright holders Name & Address
; as listed above are included clearly and visibly in the documentation
; for such product.
;
; The copyright holder offers no warranty with this code whatsoever,
; including its fitness for any particular purpose. Neither shall he
; be liable for damages of any kind that may arise from its use.
;
;
; IF YOU THINK THIS CODE IS USEFUL:
;
; If you think this code has had some value to you, and in particular
; if you consider using all or parts of it in your own product, you
; may want to consider a smaller or larger donation to the author
; (Name & Address above) who spend his late night hours putting
; it together.
;
; As to the size of a such donation this is entirely up to your own
; judgement. It is suggested that you simply consider the value this
; code has had to you, the time you saved not having to write it your
; self... that should help you determine the right amount.
;
; Please notice that such donations are an entirely voluntary contribution.
; This holds true whatever your purpose is for using this code, and whatever
; the type of product and distribution you work with. The author has nothing
; against commercial software distribution and does not have any reason
; to restrict developers of commercial products in their use of this code.
;------------------------------------------------------------------------------
; COMPILING: masm tsrdemo2;
; LINKING: link tsrdemo2;
; exe2bin tsrdemo2 tsrdemo2.com
;------------------------------------------------------------------------------
; Revisions
; Brandenborg 87.02.14 Added copyright notice & checked comments
; Brandenborg 87.02.17 Added full AX value in Set Ext Err call
; Brandenborg 87.02.25 Went through to optimize things
; Brandenborg 87.02.28 Added auto INT28 invocation in INT16 handler
; Brandenborg 87.03.01 Added INT21 filter for recursion onto console stack
; Brandenborg 87.03.02 Final cleanup of comments etc.
; Brandenborg 87.03.10 INT28 handler chains AFTER popup actions
; InitPopup: INT21.33 (AL=2) not allowed for DOS 2.x
; InitPopup: Set ext err info uses all regs
;==============================================================================
;==============================================================================
; 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 SEGMENT
;==============================================================================
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 'tc' ;INT16h AX val to get MyId
MyId equ 'TC' ;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
;==============================================================================
; 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
; ------------ 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 DEMO 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 LeftShift OR RightShift ;shift state IF HotIsShift=FF
HotKeySeq db LeftDown,LeftUp,LeftDown,LeftUp
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 8 dup (0) ;all regs of ext err info
;==============================================================================
; 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
OldInt23 label dword ;^C of process we steal
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
;==============================================================================
; 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 IT'S 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 MACTHED 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
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 = 01
; 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
;==============================================================================
OurInt28 proc far
assume ds:nothing, es:nothing, ss:nothing
; ------------ ENSURE NO RECURSION ON CRITICAL INT28 CODE
pushf ;save original flags
sti ;we'll manage INT's after this
test TsrMode,InInt08 OR InInt28 OR In28Call OR InPopup
jz NowIn28 ;continue if not recursion
; ------------ PASS CONTROL TO OLD BIOS28, ORIGINAL FLAGS ON STACK
GoOld28: popf ;restore original flags
cli ;in case others forgot
jmp OldInt28 ;call TSRs loaded before this
; ------------ ENTER CRITICAL INT28 CODE, ORIGINAL FLAGS ON STACK
NowIn28: 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
jmp short GoOld28 ;we have nothing more to say
OurInt28 endp
;==============================================================================
; NopInt - DUMMY IRET INSTRUCTION USED BY EMPTY INT HANDLERS
;==============================================================================
NopInt: iret ;immediate return
;==============================================================================
; 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
; CALL POPUP ROUTINE
; RESTORE USER INTERRUPT VECTORS
; RESTORE PROCESS AND SYSTEM INFO
; CLEAR InDosClr FLAG TO PREVENT UNSAFE INT28 CALLs
; 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
mov OldExtErr[6],dx
mov OldExtErr[8],si
mov OldExtErr[10],di
mov OldExtErr[12],ds
mov OldExtErr[14],es
Dos3Saved:
; ------------ SAVE CURRENT BREAK STATE, RELAX BREAK CHECKING
mov ax,3300h ;to get current BREAK value
int 21h ;now, DL=current BREAK
mov OldBreak,dl ;save current level
mov ax,3301h ;to set BREAK from DL
xor dl,dl ;DL=0=relax checking
int 21h ;current level in DL
; ------------ 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 Popup ;finally!
; ------------ 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 ;DOS ctrl-C
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
; ------------ RESTORE USER REGS
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
;==============================================================================
; DATA FOR POPUP ROUTINE
;==============================================================================
DosReadMsg db 13,10,'Reading DOS CON (press <Enter> to terminate)',13,10
DosReadLen equ $-DosReadMsg
BiosReadMsg db 'Reading BIOS keyboard (press any key... )',8,8
BiosReadLen equ $-BiosReadMsg
DoneMsg db ' key pressed, exit from TSR DEMO)',13,10
DoneLen equ $-DoneMsg
Scratch db 80 dup (?)
;==============================================================================
; 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).
;==============================================================================
Popup proc near
assume ds:Cseg, es:nothing, ss:nothing
mov ah,40h ;DOS write handle
mov bx,1 ;standard output handle
mov dx,offset DosReadMsg ;DS:DX=str to write
mov cx,DosReadLen ;CX=# chars to write
int 21h ;output that string
mov ah,3fh ;DOS read handle
xor bx,bx ;standard input handle
mov dx,offset Scratch ;scratch buf for key
mov cx,80 ;read till CR hit
int 21h
mov ah,40h ;read from BIOS msg
mov bx,1
mov dx,offset BiosReadMsg
mov cx,BiosReadLen
int 21h
xor ah,ah ;to let BIOS wait for key
int 16h ;now, key was pressed
mov ah,40h ;write confirm msg
mov bx,1
mov dx,offset DoneMsg
mov cx,DoneLen
int 21h
ret
Popup endp
;==============================================================================
; TSR IRON CURTAIN - HE WHO CROSSES THIS CURTAIN WILL BE GONE AFTER TSR!
;==============================================================================
TsrCurtain: ;TSR memory break
;==============================================================================
; NON-RESIDENT MESSAGES FOR INIT
;==============================================================================
BannerMsg label byte
db 13,10
db '<<<<<< TSR DEMO >>>>>>',13,10
db ' Thomas Brandenborg',13,10
db ' Version 2.01',13,10,10
db '$'
FirstMsg label byte
db 'Pop up routine installed resident.',13,10
db '$'
SecondMsg label byte
db 'TSR DEMO already loaded.',13,10
db '$'
HotKeyMsg label byte
db 'Hit <Left Shift> twice to pop up!',13,10,10
db '$'
Dos1Msg label byte
db 'OOPS!',7,13,10
db 'Must use DOS release 2.00 or later!',13,10,10
db '$'
BadDosMsg label byte
db 'OOPS!',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
;==============================================================================
; Init - INITIALIZE TSR APPLICATION, ENTERED UPON DOS LOAD
;
; 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
mov dx,offset BannerMsg
mov ah,9
int 21h ;display programme banner
; ------------ 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 alr installed msg
mov dx,offset HotKeyMsg
mov ah,9
int 21h ;be kind & disp hot key
mov ax,4c00h + xSecond ;error level in AL
int 21h ;abot now
; ------------ IDIOT IS RUNNING DOS 1, LEAVE THE OLD FASHION WAY!
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 (CHIPs WAY)
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
; ------------ 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
; ------------ DISLAY MSG ABOUT HOW WELL THIS IS ALL RUNNING
mov dx,offset FirstMsg
mov ah,9
int 21h ; display confirm msg
mov dx,offset HotKeyMsg
mov ah,9
int 21h ;disp hot key
; ------------ EXIT, SAY GOOD BYE TO FRIENDS BEHIND CURTAIN!
mov es,EnvSeg ;ES=our environment copy
mov ah,49h ;to let DOS free block
int 21h ;environment copy freed
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