; ; Utility routine to test for TSR's loaded in the video RAM area. ; It looks for interrupts revectored between B000:0000 and ; B000:FFFF ; ; Depending on a switch setting, it will provide a message to the ; effect that TSRs are present in the video area. ; ; In any event, the program sets the DOS ERRORLEVEL value for ; subsequent use in a batch file. It may be necessary to check ; for the presence of vectors in an area where you are going to ; use CGA in graphics mode, or use a Herc card for other than ; text in page 0. ; ; ERRORLEVEL returns: ; ; ERRORLEVEL = 0 -> No vectors in video area - normal return ; ERRORLEVEL = 1 -> At least one vector pointing to the video ; RAM area. ; ; Switch settings: ; ; No switch -> Message suppressed ; /M -> Print error message if bad vector(s) found ; ; Usage: VIDEOTSR Look for vectors, no message if ; found; set ERRORLEVEL ; VIDEOTSR /M Look for vectors, print message ; if found; set ERRORLEVEL ; org 0100 jmp > l0 err_msg db 0d,0a,'DOS vectors found in video area', db 0d,0a,'$' msg_switch db 0 int_addr_1 dw 0 int_addr_2 dw 0 load_point dw 0b000 l0: mov si,080 mov ah,[si] cmp ah,1 ;see if any command tail or space je > l1 call find_switch jc > l1 ;did we find a switch? mov ah,[si] ;yes, get it cmp ah,'m' ;is it the right switch? je > l2 cmp ah,'M' ;or capital letter? je > l2 jmp > l1 l2: mov msg_switch,1 l1: ; ; Here is where we look to see what interrupts are trapped ; xor cx,cx mov ax,03500 ;set up call h1: push cx ;save registers push ax int 021 ;get addresses mov ax,bx ;AX is offset mov dx,es ;DX:AX is addr of interrupt mov int_addr_1,ax ;store offset away mov int_addr_2,dx ;store segment call add_seg_off ;convert to 32-bit number xchg bx,dx ;now BX:CX is int addr xchg cx,ax ; in 32-bit form mov dx,[load_point] ;where do we start xor ax,ax ;no offset from start call add_seg_off ;make 32-bitter call cmp_32 ;is int address beyond start point? jnc > h2 ;if below, can't be us - get out mov dx,[load_point] mov ax,0ffff ;DX:AX now address of end of pgm call add_seg_off ;make 32-bits call cmp_32 ;compare them jc > h2 ;if greater - beyond me mov ah,[msg_switch] ;we found one - print message? cmp ah,0 je > h4 lea dx,err_msg mov ah,9 int 021 h4: pop ax ;got here if we found pop cx ;a vector in video area mov ax,04c01 ;terminate with errorlevel = 1 int 021 h2: pop ax ;get registers back inc ax pop cx inc cx cmp cx,081 ;only look at first 128 vectors je > h3 ;rest are reserved for BASIC jmp long h1 h3: mov ax,04c00 ;terminate with errorlevel = 0 int 021 ; ; routine to compare two 32-bit quantities ; if BX:CX > DX:AX, carry bit is set ; if BX:CX < DX:AX, carry bit is cleared ; if BX:CX = DX:AX, zero flag is set ; ; all registers unchanged ; cmp_32: cmp bx,dx jae > l0 jmp > l1 l0: ja > l2 cmp cx,ax jb > l1 l2: stc ret l1: clc ret ; ; routine to form 32-bit sum of (typically) a segment and ; offset pair ; ; enter with "segment" value in DX, "offset" in AX ; returns with sum in DX:AX ; ; all other registers restored ; add_seg_off: push bx,cx xor bx,bx mov cx,4 l0: shl bx,1 shl dx,1 adc bx,0 loop l0 add ax,dx adc bx,0 mov dx,bx pop cx,bx ret ; ; Routine to get switch values from the command tail. ; ; Enter with SI pointing to some point in the command tail area. ; Returns with SI pointing to the first data item past the slash '/' ; If no slash is found, the carry bit is set. ; Also, if there is no data item after the slash, the carry is ; also set. (Data items are non-blanks and non-carriage returns) ; ; All other registers restored. ; find_switch: push ax ;save register l0: mov ah,[si] cmp ah,'/' je > l1 cmp ah,0d ;carriage return? je > l2 inc si jmp l0 l1: inc si mov ah,[si] cmp ah,020 ;a space? je l1 ;if so, keep looking cmp ah,0d ;carriage return? je > l2 ;if so, get out clc ;we must have something-clear carry l3: pop ax ;restore register ret ;and get out l2: stc ;error condition-set carry jmp l3 ;and get out end