Краткие теоретические сведения. Прерывания (Interrupt) – предусмотренный в системе механизм измене­ния естественного порядка выполнения программ с целью обработки возника­ющих событий и для

Прерывания (Interrupt) – предусмотренный в системе механизм измене­ния естественного порядка выполнения программ с целью обработки возника­ющих событий и для организации взаимодействия программ. В однозадачных системах прерывания можно рассматривать как элемент многозадачности.

В архитектуре ПЭВМ на основе процессоров x86 (реальный режим) выделяются внутренние прерывания процессора – исключения (exception), воз­никающие при исполнении инструкций, маскируемые и немаскируемые внеш­ние прерывания. Среди исключений выделяются вызванные специаль­ны­ми инструкциями генерации прерываний int; их принято выделять как про­граммные прерывания. Всего определено 256 прерываний, назначение части из которых документировано и закреплено за определенными источниками или программами-обработчиками, но большинство считаются зарезервированными для использования ОС и прикладными программами.

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

Обработчик прерывания – часть кода, подпрограмма, ассоциированная с данным прерыванием и получающая управление при его возникновении. С одним прерыванием может ассоциироваться более одного обработчика, кото­рые в таком случае образуют каскад (цепочку).

Вызов обработчика отличается от обращения к обычным подпрограммам тем, что в стеке помимо адреса возврата сохраняется также и регистр флагов. При выходе из обработчика его надо или восстановить из стека (инструкция процессора iret или retf), или отбросить (инструкция возврата с очисткой стека ret 2). Вызов обработчика и возврат из него всегда дальние (far) – адресá обработчика и точки возврата включают и смещение, и сегмент.

Резидентная программа, или TSR (Terminate-and-Stay-Resident) – в отли­чие от обычной, называемой транзит­ной, целиком или частично остается в памяти после того, как возвращает управление системе. Очевидно, выделение резидентных программ имеет смысл только в однозадачных системах.

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

В общем случае обработчик должен:

– сохранить текущий контекст выполнения, так как его вызов может произойти в любой момент времени и на фоне любой другой программы (если иметь в виду обработчик в резидентной программе);

– подготовить контекст для своего выполнения, в том числе проверить условия активизации;

– выполнить специфические функции, связанные с назначением обработ­чика;

– возможно, обратиться к сохраненному вектору прерывания;

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

Можно выделить несколько основных схем включения обработчика прерывания в каскад (цепочку).

1. Замещение – новый обработчик полностью перекрывает старый.

New_Handler PROC FAR

push … ;сохранение контекста

… ;функции обработчика

pop … ;восстановление контекста

iret ;возврат из обработчика

New_Handler ENDP

2. Предобработка – новый обработчик выполняет свои функции (напри­мер проверяет условия и модифицирует параметры) и затем передает управ­ление старому.

New_Handler PROC FAR

push … ;сохранение контекста

… ;функции обработчика

pop … ;восстановление контекста

jmp dword ptr cs:old_handler_off ;передача управления старому обработчику

New_Handler ENDP

3. Постобработка – новый обработчик обращается к старому, вновь получает управление после его завершения и затем выполняет свои функции (например, модифицирует результат)

New_Handler PROC FAR

push … ;сохранение контекста

… ;функции обработчика

pop … ;восстановление контекста

pushf ;эмуляция «обычного» вызова обработчика

call dword ptr cs:old_handler_off ; обращение к старому обработчику

iret ;возврат из обработчика

New_Handler ENDP

4. Комбинированный – например, проверка условий, в зависимости от успешности которой выполняются подготовка параметров, вызов старого обра–ботчика и модификация результатов.

New_Handler PROC FAR

push … ;сохранение контекста

… ;функции обработчика

pop … ;восстановление контекста

pushf ;эмуляция «обычного» вызова обработчика

call dword ptr cs:old_handler_off ;обращение к старому обработчику

push …

… ;продолжение функций обработчика

pop …

iret ;возврат из обработчика

New_Handler ENDP

Кроме показанных, есть более изощренные способы организации пере–ходов и вызовов процедур. Например, можно разместить ячейки, хранящие адрес, непосредственно в коде процедуры-обработчика, предварив их кодом инструкции call far или jmp far с прямой адресацией. Бóльший практический интерес представляет следующая конструкция:

pushf

push <segment_to_jmp>

push <offset_to_jmp>

retf

Её результат эквивалентен «обычному» jmp far, но в отличие от косвенной адресации точки перехода не требуется обязательное наличие пере­менной, содержащей готовый адрес. Загружаемые в стек компоненты адреса могут быть константами, вычисляемыми значениями, находиться в регистрах и так далее в любых сочетаниях. Такой прием полезен при огра­ничениях на использование переменных: например, код может находиться в ПЗУ и не иметь сегмента данных, стек же, очевидно, всегда будет только в ОЗУ. Аналог­ичным образом получается и эквивалент инструкции call far.

Если новый обработчик был установлен на внешнее прерывание и нет передачи управления старому обработчику, то перед выходом необходимо разрешить работу внешнего контроллера прерываний. В противном случае новые прерывания останутся заблокированы.

mov al, 20h

out 20h, al

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

С осторожностью следует относиться и к разрешению или запрету прерываний посредством флага IF. Стандартно он сбрасывается перед переда­чей управления обработчику, а после завершения восстанавливается предыду­щее значение всего регистра флагов. Аккуратность требуется, если сохранен­ные флаги игнорируются (возврат командой ret 2), а новое содержимое регистра FLAGS формируется самим обработчиком.

MS-DOS обеспечивает следующие основные функции прерывания int 21h для работы с прерываниями, их обработчиками и резидентными программами.

AH = 25h – установка вектора прерывания. Вход: AL – номер вектора, DS:DX – адрес нового устанавливаемого обработчика.

AH = 35h – получение вектора прерывания. Вход: AL – номер вектора. Выход: ES:BX – адрес текущего обработчика.

AH = 31h – завершение программы с сохранением ее резидентной. Вход: AL – код возврата, DX – размер оставляемой в памяти части программы (в параграфах).

Таким образом, получаем следующий «обобщенный» каркас резидентной программы, содержащей обработчик прерывания.

; начало резидентной части

Start:

jmp Init

; область переменных

old_handler_off DW ?

old_handler_seg DW ?

; код обработчиков

New_Handler PROC FAR

call dword ptr cs:old_handler_off

iret

New_Handler ENDP

; конец резидентной части

; транзитная часть – секция инициализации

Init:

… ;другие подготовительные операции

; получение и сохранение адреса старого обработчика

mov ah, 35h

mov al, <номер_вектора>

int 21h

mov cs:old_handler_off, bx

mov cs:old_handler_seg, es

; установка нового обработчика

mov ah, 25h

mov al, <номер_вектора>

mov dx, seg New_Handler

mov ds, dx

lea dx, New_Handler

int 21h

… ;другие завершающие операции

; вычисление размера резидентной части и завершение программы

; с сохранением резидентной части в памяти (TSR)

mov ax, 3100h

mov dx, offset Init

add dx, 0Fh

shr dx, 1

shr dx, 1

shr dx, 1

shr dx, 1

int 21h

END Init

Метка Start: и инструкция jmp в начале программы избыточны – при явном указании метки при директиве END выполнение программы будет начинаться именно с нее. Однако этот элемент оформления может быть легко забыт, тогда стартовой точкой программы становится первая объявленная метка. Кроме того, в формате исполняемого файла COM (модель памяти TINY) возможности управлять начальной меткой нет, управление всегда передается на начало программы. Одновременно для COM-формата потребуется директива ORG 100h для пропуска сегмента PSP.

Драйверы – особый тип резидентных программ. Первоначально пред­назначались для управления внешними устройствами, в настоящее время обеспечивают функции ввода-вывода и работу логических устройств, как явля­ющихся отображением реальных, так и виртуальных. В различных ОС для драйверов существуют специфические технологии и требования. Драйверы MS‑DOS достаточно просты и представляют собой резидентные программы, загру­жаемые ранее любых прикладных программ (включая командный интер­претатор), имеющие определенную внутреннюю структуру и поддержи­вающие определенный интерфейс.

Интерфейс с драйвером опосредован системой: прикладная программа обращается к устройству, система транслирует это обращение в запрос к драй­веру, который исполняет его и возвращает результаты. Для прикладной про­граммы все преобразования прозрачны. Драйвер включает в себя заголовок, очередь запросов, программу стратегии и программу прерывания. Заголовок – структура с фиксированным набором полей, расположенная в начале кода драйвера и исчерпывающим образом описывающая его. Передаваемый драй­веру запрос в виде структуры временно сохраняется стратегией в одно­местной очереди, затем управление передается программе прерывания, которая и обеспечивает его выполнение. Перечень функций драйвера фиксирован: ини­циализация, чтение, запись и так далее, но поддерживаться могут не все из них. Адреса соответ­ствующих процедур сводятся в таблицу в заголовке драйвера.

Кроме интерфейса запросов, драйвер при инициализации, подобно обыч­ным резидентным программам, может устанавливать обработчики прерываний.

В MS-DOS блочными считаются устройства внешней памяти, на которых может быть размещена файловая система. Прочие устройства относятся к символьным и выглядят как файлы, не связанные ни с каким логическим диском. Блочные драйверы существенно сложнее символьных.

Контрольные вопросы

1. Понятия прерывания и его обработчика.

2. Таблица векторов прерываний.

3. Особенности обработки аппаратных и программных прерываний.

4. Основные прерывания BIOS и операционной системы DOS.

5. Способы перехвата и обработки (перекрытия) прерываний.

6. Каркас обработчиков прерываний.

7. Резидентные программы.

8. Каркас резидентной программы.

9. Обработка прерывания клавиатуры, таймера.

10. Обработка программных прерываний.

Варианты заданий

4.3.1. Перекрыть прерывание клавиатуры и сделать так, чтобы одна из букв (например “a”) подменялась другой (например “b”).

4.3.2. Перекрыть прерывание клавиатуры и сделать так, чтобы все соглас­ные буквы игнорировались.

4.3.3. Перекрыть прерывание клавиатуры и сделать так, чтобы все гласные буквы заменялись на следующие по алфавиту.

4.3.4. Перекрыть прерывание клавиатуры и сделать так, чтобы вместо каждой введенной цифры вводилось две. Например, вместо “1” получалось “11”.

4.3.5. Перекрыть прерывание клавиатуры и сделать так, чтобы все введен­ные цифры заменялись на следующие по порядку.

4.3.6. Перекрыть прерывание клавиатуры и сделать так, чтобы регистр вводимых букв менялся с нижнего на верхний (или наоборот).

4.3.7. Перекрыть прерывание клавиатуры и сделать так, чтобы все вводи­мые цифры суммировались в переменной summa.

4.3.8. Перекрыть прерывание клавиатуры и сделать так, чтобы пробелы игнорировались.

4.3.9. Перекрыть прерывание клавиатуры и сделать так, чтобы вместо пробела вводился символ ввода.

4.3.10. Перекрыть прерывание таймера и сделать так, чтобы с заданным периодом (например, каждые пять секунд) на экран выводился заданный текст (например “go”).

4.3.11. Модифицировать прерывание 21h так, чтобы при выводе строки на экран функцией 09h регистр букв в строке менялся с верхнего на нижний (или наоборот).

4.3.12. Модифицировать прерывание 21h так, чтобы при выводе строки на экран функцией 09h в строке подсчитывалась сумма всех цифр, и эта сумма выводилась на экране вместо строки.

4.3.13. Модифицировать прерывание 21h так, чтобы при выводе строки на экран функцией 09h вместо строки показывалось число слов в ней.

4.3.14. Модифицировать прерывание 21h так, чтобы при вводе строки функцией 0Ah во введенной строке удалялись все пробелы.

4.3.15. Написать драйвер виртуального символь­ного устройства – генера­тор псевдослучайной последовательности (повышенной сложности).

При загрузке драйвер инициализирует внутреннюю переменную слу­чай­ным значением (можно использовать текущее время) и обновляет ее при каж­дом считывании и периодически – по истечении заданных интервалов вре­мени. Алгоритм генерации псевдослучайной последовательности может быть выбран произвольно. При чтении из созданного устройства возвращается содержимое переменной. Необходимо обеспечить корректное считывание мно­гобайтных значений.

16. Написать драйвер виртуального символь­ного устройства – текущие дата и время (повышенной сложности).

При считывании из созданного логического устройства драйвер получает дату и время, используя функции BIOS или DOS, и возвращает его программе, читающей из устройства.

Лабораторная работа №5
Сложные обработчики
и взаимодействие резидентных программ

Цели работы:

1) ознакомиться со сложными и нестандартными ситуациями, возника­ющими при разработке и функционировании обработчиков;

2) научиться решать разрешать коллизии при перекрытии прерываний и взаимодействии обработчиков;

3) научиться организовывать интерфейс с резидентными програм­мами.

Наши рекомендации