;-------------------------------------------------------------------------- ; WATCHDOG.ASM - Resident software watchdog program ; Made : P.Lameijn ; Date : 20/3/1992 ; ; Standard calls are made to the interrupts: ; - 2F (Multiplex chain interrupt) ; - 08 (Main timer-interrupt) ;-------------------------------------------------------------------------- ; declaration of constants ;-------------------------------------------------------------------------- cr equ 10 ;carriage return lf equ 13 ;line-feed bell equ 7 ;sound 'bell' term equ '$' ;string terminator called equ 0f301h ;calling sign answer equ 001f3h ;answering sign ;-------------------------------------------------------------------------- ; Macro's used in program ;-------------------------------------------------------------------------- ; end_tsr : Leave program and stay resident ; parameters: #1: Exit parameter returned in AX (00 when succesfull) ; #2: Label of first non-resident program part ; changed : ax, cl, dx ;-------------------------------------------------------------------------- end_tsr macro ;macro sets ending mov al, #1 ;adress of program mov dx, offset #2 ;for dos and termi- mov cl, 4 ;nates program body, shr dx, cl ;leaving interrupt- inc dx ;handlers resident mov ah,31h ;in memory int 21h #em ;-------------------------------------------------------------------------- ; end_normal: Leave program normally / not resident ; parameters: #1: Exit parameter returned in AX (00 when succesfull) ; changed : ax ;-------------------------------------------------------------------------- end_normal macro ;macro terminates mov al, #1 ;program normally mov ah, 4ch ;if called when al- int 21h ;ready installed #em ;-------------------------------------------------------------------------- ; set_memory: Calculate's used memory and free's remaining memory ; parameters: #1: End-of-program label (inclusive stack-space if needed) ; changed : ax, bx, cl, sp ;-------------------------------------------------------------------------- set_memory macro ;macro calculates mov bx, offset #1 ;memory used by resi- mov cl, 4 ;dent part of pro- shr bx, cl ;gram and free's all add bx, 32 ;remaining memory mov ah, 4ah int 21h mov ax, bx shl ax, cl dec ax dec ax mov sp, ax #em ;-------------------------------------------------------------------------- ; click_speaker: Give's a short 'click' sound in speaker ; parameters: None ; changed : ax, cx ;-------------------------------------------------------------------------- click_speaker macro in al, 61h and al, 0fch out 61h, al mov cx, 150 ;<< length of click click: loop click or al, 002h out 61h, al #em ;-------------------------------------------------------------------------- ; get_vector: Get's the latest installed interrupt vector for a given ; interrupt ; parameters: #1: the interrupt number ; changed : ax ;-------------------------------------------------------------------------- get_vector macro ;macro returns the mov al, #1 ;interrupt vector mov ah, 35h ;if interrupt number int 21h ;is given #em ;-------------------------------------------------------------------------- ; set_vector: Set's the interrupt vector for a given interrupt ; parameters: #1: the interrupt number ; #2: the start label of the new handler ; changed : ax, dx ;-------------------------------------------------------------------------- set_vector macro mov ah, 25h mov al, #1 mov dx, offset #2 int 21h #em ;-------------------------------------------------------------------------- ; comp_vect: Get's the tsr interrupt vector for a given interrupt ; parameters: #1: the interrupt number ; changed : ax, dx, bx, es ;-------------------------------------------------------------------------- comp_vect macro mov ax, called mov bh, #1 mov bl, 0feh int 2fh mov cs:word ptr temp_vector, bx mov cs:word ptr temp_vector+2, es mov al, #1 mov ah, 035h int 21h mov cs:word ptr tab_vector, bx mov cs:word ptr tab_vector+2, es #em ;-------------------------------------------------------------------------- ; old_vector : Set's the old interrupt vector for a given interrupt ; parameters: #1: the interrupt number ; changed : ax, dx, bx, es ;-------------------------------------------------------------------------- old_vector macro mov ax, called mov bh, #1 mov bl, 0ffh int 2fh push bx pop dx push es pop ds mov ah, 25h mov al, #1 int 21h #em ;-------------------------------------------------------------------------- ; write : Write's a string to the screen ; parameters: #1: Label of text-string start-adress ; changed : none ;-------------------------------------------------------------------------- write_string macro push ax push dx mov dx, offset #1 mov ah, 09h int 21h pop dx pop ax #em ;-------------------------------------------------------------------------- ; conv_parm: Converts parameter on command-line to lower-case ;-------------------------------------------------------------------------- conv_parm macro mov cl, command_len cmp cl, 00h jz conv_end cmp command_parm,'A' jl conv_end cmp command_parm,'Z' jg conv_end add command_parm, 20h conv_end: #em ;-------------------------------------------------------------------------- ; free_memory: de-allocate memory ;-------------------------------------------------------------------------- free_memory macro mov ax, called mov bx, 00ffh int 2fh push dx push cx pop es mov ax, 4900h int 21h pop es mov ax, 4900h int 21h #em ;-------------------------------------------------------------------------- ; Main program. ;-------------------------------------------------------------------------- org 02Ch envir_seg equ this word org 080h command_len equ this byte org 083h command_parm equ this byte org 100h code segment para 'code' ;set all segment assume cs:code ;register's to the assume ds:code ;code segment. assume es:code ;(.COM programs can assume ss:code ;use 1 segment) ;-------------------------------------------------------------------------- ; Now the program starts with a jump to the non-resident part. ; This part is ALWAYS located at the end, so it can be removed from memory ; after TSR installation.(It won't be needed anymore then...) ;-------------------------------------------------------------------------- start: jmp init ;-------------------------------------------------------------------------- ; Here the variable's are declared and, if requested, initialized ;-------------------------------------------------------------------------- oldvect_08h dd ? ;old int 08h vector oldvect_2fh dd ? ;old int 2fh vector temp_vector dd ? ;temp.storage tab_vector dd ? ; bad_count db 0 ;error counter count dw 1092 ;timertick counter minutes db 1 ;minute counter active_flag db 1 ;active flag installed db ? ;installed or not ;-------------------------------------------------------------------------- ; int_08h: This is the resident interrupt 08 handler ;-------------------------------------------------------------------------- int_08h: pushf pusha cmp cs:active_flag, 1 jne old_08h cmp cs:count, 0 jne dec_count dec cs:minutes cmp cs:minutes, 0 je dog_alert mov cs:count, 1092 jmp old_08h dog_alert: popa popf jmp 0f000h:0fff0h dec_count: dec cs:count old_08h: popa popf jmp dword ptr cs:oldvect_08h ;-------------------------------------------------------------------------- ; int_2fh: This is the resident interrupt 2f handler. ;-------------------------------------------------------------------------- int_2fh: cmp ax, called jne old_2fh cmp bl, 1 jne int_2fh_j1 mov ax, answer jmp int_2fh_end int_2fh_j1: cmp bl, 2 jne int_2fh_j5 mov cs:active_flag, 1 mov cs:count, 1092 cmp bh, 0 jne int_2fh_j2 mov bh, 1 int_2fh_j2: mov cs:minutes, bh old_2fh: jmp dword ptr cs:oldvect_2fh int_2fh_j5: cmp bl, 3 jne int_2fh_j10 cmp bh, 0 jne int_2fh_j6 mov cs:active_flag, 0 iret int_2fh_j6: cmp bh, 1 jne int_2fh_j7 mov cs:active_flag, 1 mov cs:count, 1092 mov cs:minutes, 1 iret int_2fh_j7: cmp bh, 2 jne old_2fh mov ax, answer mov bl, cs:active_flag iret ;-------------------------------------------------------------------------- ; If bl = 255 (0ffh) then return segment and offset of the old stored ; interrupt vector. ; The interrupt number must be in register bh ; If bh = 00h then return Environment segment and program segment in cx,dx ; Tis part is used to un-install the program ;-------------------------------------------------------------------------- int_2fh_j10: cmp bl, 255 jne int_2fh_j20 cmp bh, 00h jne int_2fh_j11 mov cx, cs:[envir_seg] mov dx, cs jmp int_2fh_end int_2fh_j11: cmp bh, 08h jne int_2fh_j12 mov bx, cs:[word ptr oldvect_08h] mov es, cs:[word ptr oldvect_08h+2] jmp int_2fh_end int_2fh_j12: cmp bh, 2fh jne old_2fh mov bx, cs:[word ptr oldvect_2fh] mov es, cs:[word ptr oldvect_2fh+2] jmp int_2fh_end ;-------------------------------------------------------------------------- ; If bl = 254 (0feh) then return segment and offset of the resident inter- ; rupt handler. ; The interrupt number must be in register bh ;-------------------------------------------------------------------------- int_2fh_j20: cmp bl, 254 je int_2fh_j21 jmp int_2fh_end int_2fh_j21: mov es, cs cmp bh, 08h jne int_2fh_j22 mov bx, int_08h jmp int_2fh_end int_2fh_j22: cmp bh, 2fh jne int_2fh_end mov bx, int_2fh int_2fh_end: iret tsr_stack: dw 128 dup(?) ;-------------------------------------------------------------------------- ; Non-resident part of program. ; Used to install, uninstall, or test if installed ;-------------------------------------------------------------------------- init: set_memory einde conv_parm mov ax, called mov bl, 1 int 2fh cmp ax, answer je init1 mov cs:installed, 0 jmp init2 init1: mov cs:installed, 1 init2: cmp command_len, 0 jnz parm_test jmp help_screen parm_test: cmp command_parm, 'u' jne parm_test1 jmp un_install parm_test1: cmp command_parm, '?' jne parm_test2 jmp help_screen parm_test2: cmp command_parm, 'i' jne parm_test3 jmp install parm_test3: cmp command_parm, 'e' jne parm_test4 jmp activate parm_test4: cmp command_parm, 'd' jne parm_test5 jmp disactivate parm_test5: cmp command_parm, 's' jne parm_test6 jmp status_report parm_test6: cmp command_parm, 'r' jne parm_test_end jmp 0f000h:0fff0h parm_test_end: jmp inval_parm ;-------------------------------------------------------------------------- ; Un-install program if possible and restore interrupts ;-------------------------------------------------------------------------- status_report: write_string copyright write_string msg_status mov ax, called mov bx, 00203h int 2fh cmp ax, answer je status_j1 write_string msg_notinst end_normal 0 status_j1: cmp bl, 1 je status_j2 write_string msg_disactive end_normal 0 status_j2: write_string msg_active end_normal 0 activate: cmp cs:installed, 1 je activate_1 jmp not_installed activate_1: mov ax, called mov bx, 00103h int 2fh jmp activated disactivate: cmp cs:installed, 1 je disactivate_1 jmp not_installed disactivate_1: mov ax, called mov bx, 00003h int 2fh jmp disactivated un_install: cmp cs:installed, 1 je un_install1 jmp not_installed un_install1: comp_vect 08h call bad_update comp_vect 2fh call bad_update cmp cs:bad_count, 0 je un_inst1 jmp uninst_error bad_update: mov bx, cs:word ptr tab_vector cmp bx, cs:word ptr temp_vector jne bad_up mov bx, cs:word ptr tab_vector+2 cmp bx, cs:word ptr temp_vector+2 jne bad_up ret bad_up: inc cs:bad_count ret cmp cs:bad_count, 0 je un_inst1 uninst_errjmp: jmp uninst_error un_inst1: write_string copyright write_string msg_uninst old_vector 08h free_memory old_vector 2fh end_normal 0 ;-------------------------------------------------------------------------- ; Install program resident if possible ;-------------------------------------------------------------------------- install: mov ax, called mov bl, 1 int 2fh cmp ax, answer jne install1 jmp load_error install1: get_vector 08h mov word ptr oldvect_08h,bx mov word ptr oldvect_08h+2,es set_vector 08h, int_08h get_vector 2fh mov word ptr oldvect_2fh,bx mov word ptr oldvect_2fh+2,es set_vector 2fh, int_2fh ;-------------------------------------------------------------------------- ; Write a message to the screen ;-------------------------------------------------------------------------- write_string copyright ;write copyright write_string msg_install ;and installmessa- end_tsr 00h,init ;ge; end resident inval_parm: write_string copyright write_string msg_invalid write_string msg_help end_normal 1 not_installed: write_string copyright write_string msg_notinst end_normal 1 load_error: write_string copyright write_string msg_loaderr end_normal 1 help_screen: write_string copyright write_string msg_help end_normal 0 uninst_error: write_string copyright write_string msg_cannot end_normal 1 activated: write_string copyright write_string msg_active end_normal 0 disactivated: write_string copyright write_string msg_disactive end_normal 0 ;-------------------------------------------------------------------------- ; Message's for screen output ;-------------------------------------------------------------------------- copyright db cr,lf,'P.Lameijn - copyright (c) ' db '1991,92',cr,lf,bell,term msg_status db 'Watchdog status-report: ',term msg_loaderr db 'Watchdog already resident ',cr,lf,term msg_install db 'Watchdog now installed',cr,lf,term msg_invalid db 'Unknown command-line parameter',cr,lf,term msg_notinst db 'Watchdog not loaded',cr,lf,term msg_cannot db 'Cannot execute watchdog un-install',cr,lf db 'Interrupt vectors have been changed ' db 'since watchdog has become resident',cr,lf db 'You most likely started another resident ' db 'program behind this one',cr,lf db 'Safe removal of watchdog is only possi' db 'ble if the other program is removed ',cr,lf db 'from memory first.',cr,lf db 'Then again run the un-install option and ' db 'reload the other program (if desired)',cr,lf db 'Watchdog stays enabled and resident. ' db '(please use /d option to disable)',cr,lf,term msg_uninst db 'Resident watchdog un-installed',cr,lf,term msg_help db 'This program is a ' db 'resident software watchdog ',cr,lf db '-----------------------------------------' db '------------------------------',cr,lf db 'The following parameters can be passed' db ' on the command-line:',cr,lf db '/d - disable watchdog, stay resident',cr,lf db '/e - enable watchdog if resident',cr,lf db '/i - install watchdog and enable',cr,lf db '/r - do not install - reset immediately',cr,lf db '/s - status report watchdog',cr,lf db '/u - un-install watchdog if possible ',cr,lf db '/? - display this message',cr,lf,cr,lf db 'You can reset the watchdog counter by ' db 'calling interrupt 2f hex with :',cr,lf db ' - ax register = F301 Hex,',cr,lf db ' - bh register = number of minutes',cr,lf db ' - bl register = 02 Hex ',cr,lf db ' calling interrrupt 2f will automati' db 'cally enable watchdog if resident',cr,lf db '--------------------------------------------' db '---------------------------',cr,lf,cr,lf,term msg_active db 'Watchdog is resident / enabled',cr,lf,term msg_disactive db 'Watchdog is resident / disabled',cr,lf,term dw 128 dup(?) ;non-resid. stack init_einde label near einde equ this byte code ends end start