;// TSRLIB.ASM - дополнительные функции

  .MODEL small
  .DATA

  public  _new_int13, _get_int_13
  public  _tsrunload
  public  _set_stack, _restore_stack

;// Стек для TSR
  extrn   _tsr_stack:near

;// Флаг обработки прерывания INT 13h.
;// Равен 1, когда работает INT 13
  extrn   _unsafe_flag:near

;// Старый вектор прерывания INT 13h
  extrn   _old_int13:near

;// Идентификатор программы для
;// мультиплексного прерывания INT 2Fh
  extrn   _tsrid:near

;// Область сохранения
old_int13 dd  0
_ds_old   dw  0
_ss_old   dw  0
_sp_old   dw  0

  .CODE

;//-------------------------------------------
;// void tsrunload(void)
;// Функция выгрузки TSR из памяти
;//-------------------------------------------
_tsrunload proc
   push di
   push si
   push bp

;// Сохраняем указатель на стек
   mov word ptr _ss_old, ss
   mov word ptr _sp_old, sp

;// Сохраняем регистр DS
   mov cs:_ds_old, ds

;// Устанавливаем BX:DX на адрес завершения
   mov bx, cs
   mov dx, offset ExitTSR

;// Вызываем мультиплексное прерывание,
;// передавая ему команду завершения
   mov ah, byte ptr _tsrid
   mov al, 01h
   int 2fh

;// Если TSR завершилась, мы не попадаем на
;// команду jmp, а переходим
;// по адресу TerminateAddr
   jmp short NotExit

ExitTSR:

;// Восстанавливаем DS и стек
   mov     ax,cs:_ds_old
   mov     ds,ax

;// Признак успешной деинсталляции
   mov     al,2

;// Восстанавливаем стек
   mov     ss, word ptr _ss_old
   mov     sp, word ptr _sp_old

NotExit:
;// Преобразуем возвращенное значение в
;// двойное слово
   cbw

   pop bp
   pop si
   pop di
   ret
_tsrunload endp

;//-------------------------------------------
;// void get_int_13_ptr(void)
;// Пересылка указателя на INT 13
;// в наш сегмент данных
;//-------------------------------------------
_get_int_13 proc
  push    es
  push    bx

;// Указатель на INT 13h
  les     bx,  dword ptr _old_int13
  mov     word ptr cs:old_int13, bx
  mov     word ptr cs:old_int13 + 2, es

  pop     bx
  pop     es
  ret
_get_int_13 endp

;//-------------------------------------------
;// void set_stack(void)
;// Сохранить старый стек и установить
;// стек, который будет использован для TSR
;//-------------------------------------------
_set_stack proc

;// Получаем смещение и сегмент
;// для возврата
   pop ax
   pop bx

;// Сохраняем стек
   mov word ptr _ss_old, ss
   mov word ptr _sp_old, sp

;// Устанавливаем стек для TSR
   mov ss, word ptr _tsr_stack + 2
   mov sp, word ptr _tsr_stack

;// Загружаем стек для возврата
   push    bx
   push    ax

   ret
_set_stack  endp

;//-------------------------------------------
;// void restore_stack(void) -
;// Восстанавливаем стек
;//-------------------------------------------
_restore_stack  proc
;// Получаем смещение и сегмент
;// для возврата
  pop cx
  pop bx

;// Сохраняем старый стек
  mov word ptr _tsr_stack + 2, ss
  mov word ptr _tsr_stack, sp

;// Восстанавливаем стек
  mov ss,word ptr _ss_old
  mov sp,word ptr _sp_old

;// Загружаем стек для возврата
  push bx
  push cx

  ret
_restore_stack  endp

;//-------------------------------------------
;// void far new_int13(void)
;// Новый обработчик INT 13h
;//-------------------------------------------
_new_int13 proc far
  push    ax
  push    ds

;// Устанавливаем DS на сегмент данных TSR
  mov ax, DGROUP
  mov ds, ax

;// Увеличиваем флаг _unsafe_flag
  inc word ptr _unsafe_flag

;// Восстанавливаем DS и AX
  pop ds
  pop ax

;// Вызываем прерывание
  pushf
  call    cs:old_int13

  push    ax
  push    ds
  mov ax, DGROUP
  mov ds, ax

;// Уменьшаем флаг _unsafe_flag
  dec word ptr _unsafe_flag

  pop ds
  pop ax

  ret 2
_new_int13 endp

  end
