На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 4 / Размещение резидентных копий TSR Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Размещение резидентных копий TSR

Управление некоторыми действиями DOS и работой аппаратных средств предписывает использование входа IVT. TSR также использует прерывания и входы IVT TSR для размещения резидентных копий своих программ. При этом может возникнуть необходимость размещения в памяти нескольких копий резидентных программ TSR или необходимость размещения данных, записываемых с помощью резидентной программы. Если при выполнении TSR выбирает некоторый вход IVT, то последовательность выполняемых программ активации размещает резидентную программу путем выполнения инструкции INT или проверки программного кода, указываемого входом IVT.


Какой вход IVT следует выбрать? Это, прежде всего, определяется тем, что выбор прерывания для размещения резидентной программы зависит от автора TSR. Абсолютно простой механизм отсутствует.


DOS и аппаратные средства персонального компьютера используют только некоторые из имеющихся в распоряжении входов IVT. Теоретически можно выбрать любой неиспользуемый вход. Если TSR действительно выполняет инструкцию INT, то вход IVT должен указывать на допустимую программу обработки прерывания (ISR). Однако, гарантия того, что вход IVT ее содержит, если TSR не инициализировала ее, отсутствует. Один из путей выхода из этой дилеммы "Catch 22" ("Ловушка 22") состоит в проверке входа IVT.


DOS загружает все программы на границу сегмента. Если вектор прерывания "захватила" предыдущая копия программы, то значение смещения (младшее слово) во входе IVT должно соответствовать смещению ISR в текущей программе. Так как надежда на то, что программы обработки прерываний (ISR) для двух различных программ TSR используют один и тот же вход IVT и имеют одинаковое смещение, довольно слабая, то необходимо выполнить некоторую дополнительную проверку. Пример этого приведен в листинге 4-19.


В этом примере ищется строка ASCII UniqueID; мы могли бы выполнить в программе ISR сравнение строк. Недостатком этого способа является то, что он не разрешает проблему "конфликтующих" прерываний. Если две программы TSR решили использовать один и тот же вход IVT, то практически не существует способа определения того, какую TSR загружать первой.


Начиная с версии 3.0 DOS, фирма "Майкрософт" документирует многократные прерывания, что является ее первой попыткой решения проблемы "конфликтующих" прерываний. Многократные прерывания обеспечивают гарантируемые правильные входы IVT для int 2Fh и протокол размещения программ TSR. Начальные входы IVT этого прерывания int 2Fh указывают на инструкцию IRET. Каждая TSR, ожидающая использования мультиплексируемого прерывания, сначала ищет предыдущие загруженные копии своей программы, а затем устанавливает свою собственную программу ISR прерывания int 2Fh.



                Листинг 4-19.  Размещение  TSR  путем использования
                     произвольно выбранного вектора прерывания
         ----------------------------------------------------------------

         NewISRVector  EQU  ??  ; заполнение номера вектора
         OldISRxx   DD  0       ; здесь программа сохраняет старый вектор
         UniqueID   DB 'уникальная строка' ;  для идентификации ISR
         IDLength      EQU $-UniqueID ; длина строки
         NewISRxx PROC FAR      ; устанавливается программой инициализации
         ;
         ;            ...           ; все, что выполняет ISR
         ;
                      iret
         NewISRxx     ENDP
         Locate       PROC  NEAR
                      mov al,NewISRVector ; al <== номер вектора
                      mov ah,35h        ; ah <== получение функции вектора
                                        ; прерывания
                      int 21h ;  запрос к DOS для вектора прерывания
                        ret   ;   es:bx имеет адрес ISR
         LocateISR    ENDP
         CheckISR     PROC  NEAR
                      cmp   bx,OFFSET NewISRxx ; существующее смещение
                                    ; хорошее
                      jnz   done    ; если не 0 -- нет
                      mov si,OFFSET UniqueID ;  si <==  смещение  UniqueID
                      mov di,si              ; di <== смещение UniqueID
                      mov cx,IDLength     ;  cx <== длина идентификатора
                      cld
                      repnz  cmpsb  ; сравнение идентификаторов
         done:        ret           ; возврат :
                                    ; zr=1 ==> результат установлен
         CheckISR ENDP ;  zr=0 ==> результат не установлен

         TSRResdnt  PROC   NEAR ; определяет резидентная ли TSR
                      call LocateISR ;  получение адреса ISR
                      call CheckISR  ; проверяет идентификатор ID
                       ret           ; и возвращает:
                                     ; zr=1 ==> результат установлен
                                     ; zr=0 ==> результат не установлен
         TSRResdnt    ENDP
         ----------------------------------------------------------------

TSR сама осуществляет поиск резидентных копий путем загрузки уникального идентификатора в регистр AH, нуля в регистр AL и выполнения инструкции int 2Fh. Программа ISR 2Fh проверяет значение в регистре AH. Если ISR распознает идентификатор, то она устанавливает AL=00fh и возвращает управление по инструкции IRET; в противном случае она переходит к ранее сохраненной ISR int 2Fh. В конце концов, либо будет достигнут конец этой цепочки, либо ISR распознает значение в регистре AH.


Снова возможны конфликты. Для их разрешения TSR должна выбрать дополнительные проверки. Для облегчения этой проверки можно расширить протокол прерывания int 2Fh, но при этом следует иметь в виду, что стандарты на дополнительные проверки отсутствуют. Необходимо защищать программу. Один из возможных подходов иллюстрирует листинг 4-20.


Фактически, получение положительного ответа на запрос int 2Fh AL=0 означает, что ответила некоторая TSR. ISR int 2Fh, показанная в листинге, отвечает на функцию AL=1 путем возврата ее сегмента кодов в регистре ES. TSR, сделавшая начальный запрос, может использовать это значение для нахождения некоторой уникальной строки. Если строки совпадают между собой, то можно быть уверенным, что найдена правильная ISR.


Такое расширение протокола многократного прерывания не является стандартным. Отсутствует гарантия того, что некоторая другая TSR будет выполняться в ответ на запрос int 2Fh AL=1. Обнуление регистра ES перед выполнением этого второго запроса позволяет, по крайней мере, знать, что ответившая TSR возвращает некоторое значение в регистре ES. (Вам конечно известно, что TSR не должна загружаться в сегмент 0).



                 Листинг 4-20.  Размещение TSR путем использования
                           мультиплексируемых прерываний
         ----------------------------------------------------------------

         OurID EQU   81h       ;  TSR выбирает значение AH
         OldISR2f  LABEL  FAR  ;здесь  сохраняется старый вектор int 2Fh

         UniqueID    DB   'уникальная строка' ;для идентификации TSR
         IDLength    EQU     $-UniqueID ; длина строки
         OldInt2f    DD      0       ; здесь программа инициализации запи-
                                     ; сывает начальный адрес ISR
         NewISR2f    PROC    FAR     ; новая ISR int 2Fh
                     cmp     ah,OurID ; запрос для нас?
                     jz      ItsMe   ; если 0 -- для нас
                     jmp     cs:Oldint2f ; передача запроса
         ItsMe:      or      al,al   ; загрузка проверена?
                     jnz     GetAddress ; если не 0 -- нет
                     mov     al,0ffh ; загружена
                     iret    ; возврат
         GetAddress:
                     cmp     al,1    ; проверен ли адрес?
                     jnz BadFunction ; если не 0 -- нет
                     push cs ; возврат сегмента в ES pop es iret
         BadFunction:
                     stc             ; индуцирует ошибку
                     iret
         NewISR2f    ENDP
         LocateISR   PROC    NEAR
                     mov ax,OurID SHL 8 ;  ожидание чего-либо?
                     int 2Fh
                     cmp al,0ffh ;  проверка выдаваемого ответа
                     jnz NotFound ; не  0  ==> нет ответа
                     xor ax,ax ;  затирание сегмента
                     mov es,ax ; проверка выдаваемого ответа
                     mov ax,(OurID SHL  8) OR 1
                               ;  запрос сегмента
                     int 2Fh
                     jc NotFound ;если cy=1,  то это не нам
                     xor ax,ax  ;  изменения  ES проводились?
                     mov bx,es ; если изменения ES не проводились
                     cmp bx,ax
                     jz  NotFound ; изменения ES не проводились
                     lea bx,NewISR2f ; ES:BX имеет адрес ISR
                     clc              ; индикация успешна
                     ret              ; возврат
         NotFound:   stc
                     ret
         LocateISR   ENDP
         TSRResdnt PROC  NEAR  ;  определяет  резидентная  ли   TSR
                     call LocateISR  ;  получает  адрес  TSR
                     jc  NotLoaded
                     call CheckISR ; проверяет идентификатор ID
                     ret              ; возврат
                                      ; zr=1 ==> установлена
                                      ; zr=0 ==> не установлена
         NotLoaded:  or      al,1     ; установка zr=0
                     ret              ; возврат
         TSRResdnt   ENDP
         ----------------------------------------------------------------

Заметим, что TSR не может просто так перехватывать прерывание int 2Fh. Если некоторая другая TSR, загружаемая позже других, "захватит" этот вектор прерывания, то вход IVT будет указывать не на первую TSR, а на загруженную позже других.


НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz