;
;----------------------------------------
; DOSMON - DOS Activity Monitor
;----------------------------------------
;
; This program will terminate and stay resident.  It intercepts the
; DOS service interrupt and displays status information on the
; screen during DOS service execution periods.
;
; S.H.Smith, 15-may-86
; converted to real assembly, sped up, and made smaller by
; jack velte 1301 441-2008  velte@mimsy.umd.edu
;

RESLEN    equ  init - dosmon + 256

code    segment byte public 'text'
        assume cs:code, ds:code
        org     100h

;----------------------------------------
; startup entry point
;----------------------------------------
dosmon  proc    near
        jmp short init  ;install
dosmon  endp

; segment address for display memory
; filled in by startup code
display_seg     dw      ?
twiddle_idx     dw      ?       ; twiddle display index
twiddle_char    db 'Ä\³/'       ; twiddle display characters

;----------------------------------------
; new DOS service interrupt
;----------------------------------------
;
new21 proc far
        push ds
        push es
        push bx         ; save entry registers
        push ax

        mov ax, cs:display_seg          ; get display segment into es
        mov es, ax
;
;----------------------------------------
; prepare display with blanks
;
        mov ax, 0f20h           ;space with attribute of 15
        mov es:[94h], ax
        mov es:[96h], ax        ;set attribute of the function code locations
        mov es:[98h], ax
;
;----------------------------------------
; display the rotating twiddle character
;
        mov bx, cs:twiddle_idx  ;get twiddle index
        inc bx
        mov al, bl              ;advance to next twiddle position
        and al, 3               ;bx=bx mod 4 to rotate through twiddles
        mov bl, al
        mov cs:twiddle_idx, bx  ;save next twiddle index

        mov ah, cs:[twiddle_char + bx]  ;get the next twiddle character
        mov es:[94h], ah                ;put twiddle status on screen
;
;----------------------------------------
; display the DOS service number in hex
;
        pop bx
        mov ax, bx              ;get the dos function code into ah

        and ah, 0fh
        add ah, 30h             ;convert low digit to hex

        cmp ah, 3ah             ;handle A..F
        jb foo
        add ah, 7
foo:
        mov es:[98h], ah        ;and set LSB on screen

        mov ax, bx              ;get fresh copy of function code into ah

        shr ah, 1               ;move down bits for high digit
        shr ah, 1
        shr ah, 1
        shr ah, 1               ;make high byte hex and put on screen
        and ah, 0fh
        add ah, 30h

        cmp ah, 3ah             ;handle A..F
        jb bar
        add ah, 7
bar:
        mov es:[96h], ah                ;set MSB on screen

;----------------------------------------
; perform the DOS service function
;
        mov ax, bx      ; we've been saving it here.
        pop bx
        pop es          ;restore initial entry registers
        pop ds
;
        db 0eah         ;   pass to original int21 code
int21ofs        dw ?    ; *** self-modifying code:
int21seg        dw ?    ; *** JMP FAR PTR xxxx:yyyy

new21   endp


;----------------------------------------
; startup code
;----------------------------------------
; determine where the video ram is.  this is done by putting a special
; character on the screen and then looking for it in the various video
; ram locations.
;
init proc near
        push cs
        pop ds          ; get cs in ds

        mov ah, 3       ;get cursor position
        int 10h         ;video bios service

        push ax
        push bx
        push dx          ;save it for later

        mov dx, 0
        mov ah, 2                ;home the cursor
        int 10h

        mov ah, 0Ah
        mov al, 88h              ;display a funny char at cursor
        mov cx, 1
        int 10h
;
; move cursor back to original position
;
        pop dx
        pop bx
        pop ax
        mov ah, 2
        int 10h
;
; look for MONO video ram
;
        mov dl, 88h
        mov ax, 0b000h
        mov es,ax
        cmp dl, es:[0]
        jz foundvideo
;
; look for COLOR video ram
;
        mov ax, 0b800h
        mov es, ax
        cmp dl, es:[0]
        jz foundvideo
;
; couldn't find video ram; display a message and abort
;
        lea dx, errormsg
        mov ah,9
        int 21h          ;display error message

        mov ah, 4ch     ; terminate with error code
        mov al, 1
        int 21h

errormsg:
        db "ERROR: Can't find display memory$"


foundvideo:
        mov cs:display_seg, ax           ;set the display segment
;
;----------------------------------------
; display the program signon message now that we are sure
; that we can be installed
;
        lea dx, signon_msg
        mov ah, 9
        int 21h          ;display signon message

        mov     es, ds:[002Ch]
        mov     ah, 49h         ; free up our copy of the environment
        int     21h

;----------------------------------------
; now install new interrupt handler
;
        mov ax,0
        mov es,ax
;
; save old DOS service vector
;
        mov     ax, 3521h
        int     21h
        mov     int21ofs, bx        ; save old int21
        mov     int21seg, es        ;
        mov     ax, 2521h           ; install new vector
        lea     dx, new21           ; ptr to our routine
        int     21h

;
; set last resident code offset
; and terminate-and-stay-resident
;
        mov     dx, RESLEN      ; size of our interrupt handler
        test    dl,0Fh             ; see if it's on a paragraph boundary
        sahf
        mov     cl, 4
        shr     dx, cl          ; convert bytes to paragraphs
        lahf                    ; paragraph aligned?
        jz     gotsr            ;   yes, we're done
        inc     dx              ; round to next paragraph
gotsr:  mov     ax, 3100h       ; terminate and stay resident
        int     21h
init    endp


; a signature in bytes
signon_msg:
        db 0ah, 0dh, "DOSMON - DOS Activity Monitor", 0ah, 0dh
        db "S.H.Smith, 15-May-86", 0ah, 0dh
        db "jack velte, may 89", 0ah, 0dh, "$"

code      ends
              end           dosmon
