;
INCLUDE STDMAC.INC ; включение описания макробиблиотеки
; ==== НАЧАЛО ПРОГРАММНОЙ СЕКЦИИ ===============================
init28 SEGMENT
ASSUME cs:init28
ASSUME ds:init28
ORG 0
SEG_ORG EQU $
ORG 0100h
main PROC FAR
start: jmp init ; пропуск памяти "старого вектора"
old_v dd ? ; пространство для запоминания старого вектора
entry: jmp first ; пропуск "идентификации"
db 'TEST ROUTINE'
first: @SwapNewStack ; макрос для переключения в новый стек
cmp go_switch,ON ; проверка если я активна
jne bypass ; да - продолжить для выхода
mov go_switch,OFF ; нет - установка переключателя
; активна
;
; < ЗДЕСЬ ИДЕТ ВАША РЕЗИДЕНТНАЯ ПОДПРОГРАММА >
;
mov go_switch,ON ; установка состояния неактивна
bypass: @SwapOLDStack ; установка стека (и включение данных)
jmp cs:exit ; переход к подпр-ме обслуж-я прерыв-я
exit dd ?
go_switch dw ?
- 3-64 -
db 32 dup ('stack ')
TOS EQU $
LAST_BYTE EQU $
;
; ===== СЕКЦИЯ ИНИЦИАЛИЗАЦИИ - ПОСЛЕ ЗАГРУЗКИ НЕ НУЖНА =========
;
init: mov go_switch,OFF ; предупреждение активизации
mov ah,35h ; получение адреса вектора
mov al,VECT_NUM
@DosCall
mov word ptr exit,bx ; сохранение указателя IP для
; выхода
mov word ptr exit+2,es ; сохранение указателя CS для
; выхода
mov word ptr old_v,bx ; сохранение указателя IP для
; удаления
mov word ptr old_v+2,es ; сохранение указателя CS
; для удаления
mov ah,25h ; установка нового указателя
mov al,VECT_NUM
mov dx,offset entry ; установка указателя IP
; ... (CS и DS аналогично)
@DosCall
mov go_switch,ON
mov dx,9offset LAST_BYTE - SEG_ORG + 15) shr 4
mov ah,31h ; завершить и оставить резидентной
@DosCall
;
main ENDP
init28 ENDS
END start
----------------------------------------------------------------
Другие возможные точки вставки "заплат" зависят от типа ре-
зидентной подпрограммы и частоты, с которой она должна вызывать-
ся. Например, подпрограмма буферизации печати - print spooler
routine (которая печатает файлы во время выполнения других прог-
рамм) не только должна прерывать прерывание для активации пере-
дачи символов в принтер, но также должна прерывать любое обраще-
ние к MS-DOS, которое использует принтер, так, чтобы не
возникали конфликты. Рис.3-16 показывает прерывание буферизации
печати int 28h для активации самой себя и прерывание int 21h для
охраны самой себя от конфликтов при доступе к принтеру.
- 3-65 -
---------------
прерывание | ... | Таблица векторов се-
---------------------| Int 21 IP/CS |<---------------------
| прерывание | ... | мейства микропроцес-|
| -------------------| Int 28 IP/CS |<----- соров 8086 |
| | | ... | | |
| | --------------- |Внешний вызов |
| | --------------- | Int 28h |
| | ------>| MS-DOS |------ MS-DOS |
| | | | ... | |
| | --------|-------| Коды Int 21 |<----------------- |
| | | | | ... | | |
| | | -------| Коды Int 28 |<------- Возврат | |
| | | --------------- | в | |
| | | --------------- | MS-DOS | |
| --|--------------->| Подпрограмма | | из пре- | |
| | | буферизации | | рывания | |
| | | ... | | Int 21h | |
| | | Коды печати |------- | |
| | | ... | | |
| | |---------------|Передача Int 21h | |
----|--------------->|Проверка Int 21|------------------ |
| --------------- |
| --------------- |
| | Программа | |
| | пользователя | |
| | ... | |
--------------->| Int 21h |----------------------------
Возврат Int 21 в | ... |
программе пользова- ---------------
теля
Рис.3-16. Использование векторов прерываний подпрограммой
буферизации печати
При любом использовании векторов прерываний для реализации
некоторого подобия параллелизма, имеется риск "выхода" из выпол-
нения программы, осуществляющей непосредственный доступ к аппа-
ратным средствам. Например, если для обеспечения некоторых воз-
можностей устанавливается вектор прерывания клавиатуры и если
другая программа обходит вектор клавиатуры и вместо этого осу-
ществляет чтение с аппаратных средств, то резидентная подпрог-
рамма не получает управления. Этот эффект может легко произойти,
если устанавливается несколько резидентных программ, потому что
каждая программа должна обойти MS-DOS для выполнения ввода/выво-
да. Например, если и подпрограмма буферизации печати и резидент-
ная подпрограмма устанавливаются для печати содержимого видео-
дисплея, и обе активизированы в одно и тоже время, то произойдет
конфликт. Эти проблемы могут также возникнуть и при установке
имеющихся в наличии коммерческих резидентных подпрограмм. У
пользователей существует только один способ защитить себя - это
установка только одной подпрограммы для проверки конфликтов.
REMOVE - пример интегрированной программы
Программа удаления REMOVE (смотри листинг 3-13) предназначе-
на для удаления установленной резидентной программы и базируется
на примере, данном в INIT28 (смотри листинг 3-12). Программа
REMOVE пытается идентифицировать резидентную программу путем
- 3-66 -
дампирования байтов, следующих за точкой входа, и отображает 4
байта, предшествующих точке входа, как адрес предыдущего векто-
ра. Кроме того, программа REMOVE предполагает, что резидентная
программа представлена в формате .COM, и пытается разместить ад-
реса PSP и блока среды. Всю эту информацию программа REMOVE пре-
доставляет пользователю для принятия решения о том, удалять ре-
зидентную программу, вставленную в вектор прерывания, или нет.
Листинг 3-13. REMOVE - удаление резидентной подпрограммы,
вставленной в качестве "заплаты" в вектор
прерывания
----------------------------------------------------------------
PAGE 60,132
;===== REMOVE - Этот файл генерирует программу типа .COM =======
;===== Удаление резидентной подпрограммы, вставленной в ка- ====
;============ честве "заплаты" в вектор прерывания =============
;(Interrupt Service Routine (ISR) - это подпрограмма обслужива-
; ния прерывания))
OLD_IP EQU -4 ; Возможное положение IP в ISR
OLD_CS EQU -2 ; Возможное положение CS в ISR
ID EQU 0 ; Положение 1-го байта в ISR
IRETOP EQU 0CFh ; Код операции IRET
;
;===== МАКРООПРЕДЕЛЕНИЯ ДЛЯ УТИЛИТ =============================
;
INCLUDE STDMAC.INC ; Включение макроопределений
;
remove SEGMENT
ASSUME cs:remove
ASSUME ds:remove
; Определение необходимых адресов внутри сегмента программого
; префикса (PSP)
ORG 2Ch
env_adr LABEL WORD ; Адрес указателя среды
ORG 80h
cmd_len db ? ; Длина командной строки
new_len db ? ; Длина строки буферизованного чтения
cmd_buf db ? ; Строка командной строки
;===== НАЧАЛО ПРОГРАММНОГО КОДА ================================
ORG 0100h
main PROC FAR
start:
mov ch,byte ptr [cmd_len]
cmp ch,0 ; аргумент обеспечен ?
jnz have_cmd
; Аргумент не обеспечен - приглашение пользователя для указания
get_cmd:
@DisStr request ; приглашение для номера вектора
mov byte ptr [cmd_len],80
mov dx,offset cmd_len
mov ah,0Ah ; выполнение буферизованного чтения в
@DosCall ; буфер командной строки
@DisChr LF ; новая строка
mov ch,new_len ; получение размера введенного текста
cmp ch,0 ; просмотр, ответил ли пользователь?
jz abort ; если нет, то предполагается выход
inc ch ; установка ответа для приведения в
- 3-67 -
; соответствие
have_cmd:
cmp ch,3 ; проверка для правильного # символов
je ok_cmd
@DisStr bad_cmd ; если ошибка, то некорректный флажок
abort: jmp finis
ok_cmd: mov bx,offset cmd_buf
mov ch,2 ; грамматический разбор 2 символов
call get_hex ; преобразование # в буфер в двоичн.
jc abort ; выход, если ошибка преобразования
mov vec_num,al ; сохранение адреса вектора
mov ah,35h ; получение указателя вектора из MS-DOS
@DosCall
mov vec_ip,bx ; сохранение IP вектора
mov al,vec_num ; восстановление номера вектора
call show_vector ; отображение содержимого вектора
@DisStr askresv
call yesno
jc no_restore ; нельзя желать восстановить вектор