Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
TURBO_PASCAL.doc
Скачиваний:
8
Добавлен:
01.07.2025
Размер:
8 Мб
Скачать
☆

16.5. Работа с прерываниями ms-dos

Вызов системных функций MS-DOS реализован в виде прерываний. Каждое прерывание, будучи активизированным, может открывать доступ к множеству различных функций. Так, например, прерывание с номером 16H дает доступ к функциям опроса клавиатуры на уровне операционной системы, прерывание с номером 25H управляет чтением диска и т.д. Особую роль играет прерывание с номером 21H. Оно открывает доступ к нескольким десяткам функций, образующим собственно операционную систему.

Работая на ассемблере, программист при необходимости вызова той или иной функции MS-DOS должен предварительно загрузить в определенные регистры процессора номер функции и ее аргументы и вызвать прерывание по его номеру. Список прерываний, связанных с ними функций и их аргументов, занял бы целую книгу и здесь не приводится. Заинтересованных мы отсылаем к техническим описаниям MS-DOS конкретных версий и БСВВ (BIOS) конкретных ПЭВМ.

А как быть тем, кто знает Паскаль, но не знаком с машинным кодом? Ответ прост: пользоваться процедурами модуля DOS, поддерживающими обращение к функциям MS-DOS (или прерываниям), прямо из Паскаль-программ (но знать, что делает прерывание и как выполняется, конечно, необходимо). Список этих процедур приводится в табл. 16.6.

Таблица 16.6

Процедура

Действие

GetIntVec(N : Byte; VAR Adress : Pointer)

Возвращает в Adress адрес подпрограммы прерывания с заданным номером N

SetIntVec(N : Byte; Adress : Pointer)

Устанавливает в DOS новую подпрограмму прерывания с номером N, замещая старое значение адреса на Adress {369}

Intr(N : Byte; VAR R : registers)

Активизирует программное прерывание N, передавая ему номер функции и параметры в переменной R

MsDos(VAR R : Registers)

Специализированный вызов прерывания с номером 21H

В таблице введен новый тип Registers. Он определен в модуле DOS и является записью с вариантами:

TYPE

Registers = RECORD

case Integer of

0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : Word);

1:(AL, AH, BL, BH, CL, CH, DL, DH : Byte);

END;

Переменные такого типа служат для доступа к регистрам микропроцессора при вызовах Intr и MsDos. Вариант 0 позволяет обращаться к 16-разрядным регистрам (парам), а вариант 1 — к 8-разрядным ячейкам процессора. Специально об указании варианта заботиться не следует. Если написать, например,

USES DOS;

VAR

R1, R2 : Registers;

BEGIN

R1.AX := $01FF;

R2.AL := $CA;

…

END.

то компилятор сам разберется с типом поля записи по его имени.

16.5.1. Чтение и перестановка адресов подпрограмм прерываний

Действия с перестановкой адресов — работа несложная, но «опасная». Прежде чем пояснить этот тезис, дадим общее понятие о предмете. При загрузке операционной системы в ОЗУ модуль БСВВ располагает в самом начале памяти таблицу векторов прерываний. Под этим красивым названием хранится простой список адресов подпрограмм ОС или аппаратной части, выполняющих действия по тому или иному прерыванию. Выполнение прерывания означает {370} среди прочего чтение адреса из этой таблицы и передачу управления подпрограмме по этому адресу.

Очевидно, что если написать свою программу обработки какого-нибудь прерывания (что непросто без специальных знаний) и «подставить» ее адрес вместо «настоящего», то ряд функций ОС будет выполняться этой программой. Так работают все резидентные программы. Находясь постоянно в памяти, они перехватывают нужные им прерывания и анализируют их. Например, если резидентная программа активизируется нажатием каких-либо клавиш (таковы SideKick, драйверы клавиатуры и т.п.), то она настраивает на себя прерывания 9 и 16H, которые «включаются» при каждом нажатии клавиши на клавиатуре. Далее анализируется, что именно было нажато, и если это была запускающая комбинация, то начинает работать сама резидентная программа. Если же нет, то вызывается настоящая подпрограмма этого прерывания, как будто ничего не было. Чтение адреса подпрограммы отработки прерывания осуществляется процедурой

GetIntVec( N : Byte; VAR Adress : Pointer ).

Задав через параметр N номер интересующего нас прерывания, после вызова получим в переменной Adress адрес его подпрограммы, вызов процедуры вполне безопасен. Установка адреса новой подпрограммы делается процедурой

SetIntVec( N : Byte; Adress : Pointer ).

Здесь параметр N по-прежнему содержит номер прерывания, а параметр Adress должен содержать адрес специально оформленной процедуры, которую надо подставить в таблицу векторов.

Эксперименты с этой процедурой в высшей степени опасны: ошибка в задании адреса или неверное оформление процедуры способны, используя термины жаргона программистов, послать вектор прерывания «в космос». Реально же это означает полную непредсказуемость дальнейшего поведения ПЭВМ. Хорошо, если она просто «зависнет», а то — можно лишиться информации на диске и испортить ее.

Жесткие требования предъявляются к оформлению собственно процедур обработки прерываний. Описание заголовков таких процедур, должно выглядеть следующим образом:

PROCEDURE IntProc(Flags, CS, IP, АХ, ВХ, СХ, DX,

SI, DI, DS, ES, ВР: Word); INTERRUPT; {371}

Список параметров представляет собой список регистров микропроцессора. Он может быть короче: разрешается опускать последовательности параметров начиная с первого и при этом оставлять неизменным и неразрывным оставшийся до конца список.

Например, заголовки

PROCEDURE IntProc2( SI, DI, OS, ES, BP : Word ); INTERRUPT;

PROCEDURE IntProc3( ES, BP : Word ); INTERRUPT;

верны, так как отброшены и оставлены две неразрывные части полного списка параметров, а заголовок

PROCEDURE IntProc4( Flags, ES, BP : Word ); INTERRUPT;

неверен, так как пропуск делает «дыру» в списке.

Названия параметров не должны меняться. Внутри процедуры прерывания с ними можно делать что угодно (опрашивать, изменять — одновременно с ними будет изменяться содержимое соответствующих им регистров). Процедура с указанием interrupt не может быть вызвана, как обычная процедура. Она начнет работать только после активации настроенного на нее прерывания, и она ничего не возвращает. Имена ее параметров можно использовать вне interrupt-процедуры.

Процедуры для прерываний низкого уровня (аппаратных — от клавиатуры, портов, таймера и т.п.), номера которых лежат в диапазоне от 0 до 31 (от 0 до 16H), не должны в общем случае содержать в себе вызовов процедур ввода-вывода Турбо Паскаля, команд динамического распределения памяти и вызовов функций ОС.

После того как процедура прерывания написана, ее необходимо подключить. Программа должна в этом случае иметь общую структуру, показанную на рис. 16.12.

USES DOS;

VAR

GlobalVARI, GlobalVAR2, ..., GlobalVARK : Word;

{$F+} {<-Interrupt-процедуры должны быть с таким ключом }

PROCEDURE MyInterrupt(Flags, CS, IP, AX, BX, CX, DX,

SI, DI, DS, ES, BP : Word); INTERRUPT;

VAR

... { описание локальных переменных }

Рис. 16.12 {372}

BEGIN

GlobalVAR1:=AX; { Можно снять входные параметры}

GIobaIVAR2:=Port[...]; { прерывания и запомнить их. }

...

END; { Myinterrupt }

{$F-}

VAR

N : Byte;

OldlntVectN : Pointer; { буферная переменная }

BEGIN

N := { номер заменяемого прерывания } ;

{ Сохранение исходного вектора в буферной переменной:}

GetIntVec( N, OldlntVectN );

{ Запись в вектор N адреса подставляемой процедуры: }

SetIntVec( N, SMylnterrupt );

...

{ Программа работает с подмененным прерыванием: }

Write( GlobalVARI, GlobalVAR2 GlobalVARK );

...

SetIntVec( N, OldlntVectN );

{ Всегда надо восстанавливать исходные векторы, если }

{ только программа не остается резидентной в памяти. }

END.

Рис. 16.12 (окончание)

Если потребуется модифицировать операционную систему, меняя вектора прерывания, то необходимо и желательно детально изучить техническое устройство механизма прерываний.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]