;**********************************************************; 
;*  Self High-Loading TSR Program -- 32 bytes resident!!  *; 
;*                    By Tenie Remmel                     *; 
;**********************************************************; 
 
Ideal 
Model Tiny 
P186 
Codeseg 
Org 100h 
 
Proc        Prog 
 
            mov dx,offset RName     ;Only leaves 32 bytes! 
            mov si,offset RName     ;also name offset 
            mov cx,0                ;No int. vectors 
            jmp TSRHi               ;TSR procedure 
 
RName       db 'Test',0             ;This is the resident name 
 
EndP        Prog 
 
Proc        TSRHi   ;Registers on entry: 
                    ; 
                    ;   DX = last byte of program 
                    ;   CS = segment of program

                    ;   CS:SI = resident name (8 bytes) 
                    ;   CX = Number of vectors to set 
                    ;   CS:BX = Vector list 
                    ;           
                    ; Vector list format: <offset> <number> ... 
                    ;                      -word-   -byte- 
             
            pusha                   ;Save all registers 
            push cs                 ;DS = CS 
            pop ds 
 
            mov ah,4Ah              ;Reallocate Memory 
            mov bx,1000h            ;BX = 64K 
            push cs                 ;ES = code segment 
            pop es 
            int 21h                 ;DOS services 
             
            mov ah,49h              ;Free memory 
            mov es,[2Ch]            ;Environment block 
            int 21h                 ;DOS services 
             
            mov ax,5800h            ;Get Alloc. Strategy 
            int 21h                 ;DOS services  
            push ax                 ;Save value 
            mov ax,5802h            ;Get UMB Link 
            int 21h                 ;DOS services 
            push ax                 ;Save value 
             
            mov ax,5803h            ;Set UMB Link 
            mov bx,1                ;1 = Link ON 
            int 21h                 ;DOS services 
            mov ax,5801h            ;Set Alloc. Strategy 
            mov bx,82h              ;Last Fit, UMBs First 
            int 21h                 ;DOS services 
             
            mov ah,48h              ;Allocate Memory 
            mov bx,dx               ;BX = last byte 
            sub bx,0F1h             ;BX - 100h + 0Fh 
            shr bx,4                ;BX = size in paras 
            int 21h                 ;DOS services 
            jc _NoMem               ;Jump if error 
             
            dec ax                  ;AX = MCB seg. 
            mov es,ax               ;ES = AX 
            inc ax                  ;AX = memory block 
            mov [es:1],ax           ;Set owner to itself 
            mov di,8                ;Move name to MCB:8 
            mov cx,4                ;8 bytes = 4 words 
            rep movsw               ;Move by words 
             
            mov ax,5803h            ;Set UMB Link

            pop bx                  ;to old value 
            int 21h                 ;DOS services 
            mov ax,5801h            ;Set Alloc. Strategy 
            pop bx                  ;to old value 
            xor bh,bh 
            int 21h                 ;DOS services 
             
            mov ax,es               ;AX = new CS segment 
            sub ax,0Fh 
            mov es,ax               ;ES = AX 
            popa                    ;Restore original regs 
            mov si,100h             ;SI = 100h 
            mov di,si               ;DI = 100h 
            push cx                 ;Save CX 
            mov cx,dx               ;CX = last byte 
            sub cx,100h             ;CX = length 
            rep movsb               ;Move data 
 
            pop cx                  ;Restore CX 
            jcxz _NoVects           ;No vectors to set? 
            mov ah,25h              ;Set Interrupt Vector 
            push es                 ;DS = ES 
            pop ds 
_SetIVect:  lodsw                   ;Load offset 
            mov dx,ax               ;into DX 
            lodsb                   ;Load int. number 
            int 21h                 ;Set vector 
            loop _SetIVect          ;Loop back 
 
_NoVects:   mov ax,4C00h            ;Return with code 0 
            int 21h                 ;DOS services 
 
_NoMem:     mov ax,5803h            ;Set UMB Link 
            pop bx                  ;to old value 
            int 21h                 ;DOS services 
            mov ax,5801h            ;Set Alloc. Strategy 
            pop bx                  ;to old value 
            xor bh,bh 
            int 21h                 ;DOS services 
             
            mov ax,cs               ;ES = MCB segment 
            dec ax 
            mov es,ax 
            mov di,8                ;Move name to MCB:8 
            mov cx,4                ;8 bytes = 4 words 
            rep movsw               ;Move by words 
             
            popa                    ;Restore original regs 
            push dx                 ;Save DX 
            jcxz _NoVects1          ;No vectors to set? 
            mov ah,25h              ;Set Interrupt Vector 
_SetIVect1: lodsw                   ;Load offset 
            mov dx,ax               ;into DX 
            lodsb                   ;Load int. number 
            int 21h                 ;Set vector 
            loop _SetIVect1         ;Loop back 
 
_NoVects1:  mov ax,3100h            ;TSR service, code 0 
            pop dx                  ;Restore DX 
            add dx,0Fh              ;DX = size in paras, 
            shr dx,4                ;rounded up 
            int 21h                 ;DOS services 
 
EndP        TSRHi 
 
End Prog 
 
