02/19/95 03:26pm
prer.lek
Роберт Журден "Справочник
программиста на компьютере фирмы
IBM".
А.Г.Шевчик, Т.В.Демьянков
"Справочник программиста и
пользователя" серия
"Карманная энциклопедия"
М."Кварта" 1993.
П.Нортон, Р.Уилтон "IBM PC и PS/2
руководство по
программированию" перевод
В.Н.Григорьева М "Радио и
связь" 1994
Система прерываний.
Прерывание - приостановление работы одной программы и передача управления другой при возникновении некоторого независящего от них события. При этом сохраняется возможность возврата управления прерванной программе, без потери ею работоспосодности.
Адреса подпрограмм обслуживания прерываний находятся в специальной таблице и называются векторами прерывания. В реальном режиме таблица вектров распологается в начале физической памяти; вектор имеет длину четыре байта и храниться в форме CS:IP. В защищенном режиме таблица векторов может быть расположена в любом месте и содержит более сложные дескрипторы (в режиме V86 имеется подобие таблицы реального режима).
Работа с системой прерываний может рассматриваться с двух точек зрения:
Работа с векторами прерываний;
Работа с микросхемами контроллеров прерываний (современные рашины могут не иметь отдельной микросхемы контроллера прерываний, но их регистры сохранены в адресном пространстве).
ПРИМЕЧАНИЕ: Еще раз подчеркивается, что речь идет прежде всего о реальном режиме. Попытка "попробовать" в любом другом может иметь непредсказуемые последствия.
Таблица дескрипторов прерываний защищенного режима доступна только из нулевого кольца защиты, вы можете создать или изменить ее если выполните переключение в защищенные режим самостоятельно!
При работе в режиме V86 возможно изменение образа таблицы прерываний, но последствия определяются возможностями виртуального монитора!
Работа с векторами прерываний.
Необходимость работать с таблицей прерываний может возникнуть в следующих случаях:
Как прерывание можно вызывать одну из ваших подпрограмм. Хотя вызов подпрограммы как прерывания требует больше процессорного времени, такой подход оправдан если необходимо нарушить принцип иерархичности программного обеспечения внутри одного модуля или если эта процедура используется многими Вашими программами (ее можно оставить резидентной после завершения программы настройки Вашей системы).
Второй
причиной написания прерывания
может быть использование
какого-либо отдельного
аппаратного прерывания. Это
прерывание автоматически
вызывается при возникновении
определенных условий.
Обычно BIOS инициализирует
неиспользуемые ею вектора
прерываний так, что они
указывают на процедуру,
которая вообще ничего не
делает (она содержит один
оператор IRET). Вы можете
написать свою процедуру и
изменить вектор прерываний,
чтобы он указывал на нее. Тогда
при возникновении аппаратного
прерывания будет выполняться
Ваша процедура.
Возможна подмена существующего прерывания на ваше собственное. Одно из таких прерываний это прерывание времени суток, которое автоматически вызывается 18.2 раза в секунду. Обычно это прерывание только обновляет показание часов, но Вы можете использовать его для синхронизации событий внутри Вашей программы. Другие возможности - это написание процедуры обработки Ctrl-Break если Ваша программа должна выполнять некие специфические действия перед своим завершением.
Наконец, Вы можете захотеть написать прерывание, которое дополнит одну из процедур операционной системы. В этом случае после выполнения необходимых Вам действий необходимо передать управление исходной подпрограмме обслуживания прераваний (используется "длинный" безусловный переход или дополнительное прерывание). Такой прием может понадобиться при написании резидентных программ, получающих управление при получении определенной команды с клавиатуры.
Таблица векторов прерываний занимает 1Кбайт памяти в диапазоне 00000h - 00400h. Каждому вектору отводится четыре байта в таблице и присваивается номер от 00h до FFh. При инициализации системы вектора настраиваются на подпрограммы, расположенные в ROM BIOS или DOS.
За пользователем сохраняется возможность перенастраивать вектора по своему усмотрению. Это можно сделать записав по соответствующему физическому адресу необходимое программисту значение, или обратившись к службам DOS. В любом случае необходимо позаботиться о сохранении старого вектора и восстановлении его значения перед завершением программы.
Функция 25H прерывания 21H устанавливает вектор прерывания на указанный адрес. Адреса имеют размер два слова. Старшее слово содержит значение сегмента (CS), младшее содержит смещение (IP). Чтобы установить вектор, указывающим на одну из Ваших процедур, нужно поместить сегмент процедуры в DS, а смещение в DX Затем поместите номер прерывания в AL и вызовите функцию. Функция 25H автоматически запрещает аппаратные прерывания в процессе изменения вектора, поэтому не существует опасности, что посреди дороги произойдет аппаратное прерывание, использующее данный вектор.
;---установка прерывания
PUSH DS ;сохраняем DS
MOV DX,OFFSET ROUT ;смещение для процедуры в DX
MOV AX,SEG ROUT ;сегмент процедуры
MOV DS,AX ;помещаем в DS
MOV AH,25H ;функция установки вектора
MOV AL,60H ;номер вектора
INT 21H ;меняем прерывание
POP DS ;восстанавливаем DS
;---процедура прерывания
ROUT PROC FAR
.
.
IRET
ROUT ENDP
Функция 35
прерывания 21H возвращает текущее
значение вектора прерывания,
помещая значение сегмента в ES, а
смещение в BX. Перед установкой
своего прерывания получите текущее
значение вектора, используя эту
функцию, сохраните эти значения, и
затем восстановите их с помощью
функции 25H (как выше) перед
завершением своей программы.
Например:
;---в сегменте данных:
KEEP_CS DW 0 ;хранит сегмент заменяемого прерывания
KEEP_IP DW 0 ;хранит смещение прерывания
;---в начале программы
MOV AH,35H ;функция получения вектора
MOV AL,1CH ;номер вектора
INT 21H ;теперь сегмент в ES, смещение в BX
MOV KEEP_IP,BX ;запоминаем смещение
MOV KEEP_CS,ES ;запоминаем сегмент
;---далее можно изменять вектор по своему усмотрению...
Имеется пара ловушек, которых следует избегать при написании прерывания. Если новая процедура прерывания должна иметь доступ к данным, то необходимо позаботиться, чтобы DS был правильно установлен (обычно прерывание может использовать стек вызывающей программы).
Другая неприятность может заключаться в том, что при завершении программы по Ctrl-Break вектор прерывания не будет восстановлен, если только Вы не предусмотрите, чтобы программа реакции на Ctrl-Break выполняла эту процедуру.
ПРИМЕЧАНИЕ: Не рекомендуется прямо устанавливать вектор прерываний, обходя функцию DOS. В частности в многозадачной среде операционная система может поддерживать несколько таблиц векторов прерываний и реальный физический адрес таблицы может быть известен только DOS.
Работа с аппаратными прерываниями.
Для управления аппаратными прерываниями во всех типах IBM PC используется микросхема программируемого контроллера прерываний Intel 8259 (или ее аналоги). Поскольку в каждый момент времени может поступить не один запрос, микросхема имеет схему приоритетов. Имеется 8 уровней приоритетов, кроме AT, у которого их 16, и обращения к соответствующим уровням обозначаются сокращениями от IRQ0 до IRQ7 (от IRQ0 до IRQ15). Максимальный приоритет соответствует уровню 0. Добавочные 8 уровней для AT обрабатываются второй микросхемой 8259; этот второй набор уровней имеет приоритет между IRQ2 и IRQ3. Запросы на прерывание 0-7 соответствуют векторам прерываний от 8H до 0FH; для AT запросы на прерывания 8-15 обслуживаются векторами от 70H до 77H.
Ниже
приведены назначения этих
прерываний:
Таблица аппаратных прерываний:
запрос |
прерывание |
функция |
0 |
08h |
Запрос от таймера |
1 |
09h |
Контроллер клавиатуры |
2 |
0Ah |
Вторая микросхема в AT, XT286, PS50 + или вертикальный обратный ход луча EGA/VGA |
3 |
0Bh |
Запросы от COM2 или COM4 |
4 |
0Ch |
Запросы от COM1 или COM3 |
5 |
0Dh |
НЖМД в XT или запрос от LPT2 (AT) |
6 |
0Eh |
Запросы от контроллера НГМД |
7 |
0Fh |
Запросы от LPT1 |
8 |
70h |
Часы реального времени в AT, XT286, PS50 + |
9 |
71h |
В AT, XT286, PS50 + программно переназначено на запрос 2 |
12 |
74h |
Перывание от мыши в PS50 + |
13 |
75h |
Ошибка математического сопроцессора в AT, XT286, PS50 + |
14 |
76h |
Контроллер НЖМД в AT, XT286, PS50 + |
Микросхема 8259 имеет три однобайтных регистра, которые управляют восемью линиями аппаратных прерываний. Регистр запроса на прерывание (IRR) устанавливает соответствующий бит, когда линия прерывания сигнализирует о запросе. Затем микросхема автоматически проверяет не обрабатывается ли другое прерывание. При этом она запрашивает информацию регистра обслуживания (ISR). Дополнительная цепь отвечает за схему приоритетов. Наконец, перед вызовом прерывания, проверяется регистр маски прерываний (IMR), чтобы узнать разрешено ли в данный момент прерывание данного уровня.
Существует
еще несколько внутренних регистров
для настройки микросхемы
контроллера. Все регистры доступны
через два порта с адресами 20..21h.
Если имеется вторая микросхема (для
AT), то ее адреса A0..A1h.
Перед работой контроллер должен быть проинициализирован. Инициализация осуществляется загрузкой управляющих слов (до 4-х байт). После инициализации контроллер переходит в операционный режим.
Инициализация контроллера.
Когда разрабатывался контроллер прерываний для i8085 в его схеме были допущены ошибки, поэтому при разработке контроллера для i8086 (микросхема 8259A) предусмотрели возможность его работы и в системах, построенных на базе i8085. Настройка будет рассматриваться только для систем i8086.
Порт 20h - управляющее слово инициализации ICW1:
бит 0 1 четыре слова инициализации (слово ICW4 определяет особенности взаимоотношений ведущего и ведомого контроллеров);
бит 1 1 в системе используется один контроллер;
бит 2 0 вектор 8-ми байтовый,
1 вектор 4-х байтовый;
бит 3 0 фиксация прерывания "на фронте" (в PC и AT),
1 фиксация прерывания "на уровне" (в PS/2);
бит 4 равен 1 - признак ICW1;
биты 7..5 равны нулю (для i8086).
Порт 21h - управляющее слово инициализации ICW2:
биты 2..0 равны нулю (для i8086);
биты 7..3 старшая часть номера вектора прерывания (для i8086).
Порт 21h - управляющее слово инициализации ICW3 для ведущего:
биты 7..0 1 помечаются линии к которым подключены ведомые контроллеры;
Порт 21h - управляющее слово инициализации ICW3 для ведомого:
биты 2..0 номер линии ведущего контроллера к которой подключен данный контроллер,
биты 7..3 равны нулю;
Порт 21h - управляющее слово инициализации ICW4
бит 0 1 (для i8086);
бит 1 0 завершение прерывания по команде,
1 автоматическое определение конца прерывания;
биты 3..2 режим буферизации:
0 или 1 буферизация не используется,
2 подчиненный режим буферизации,
3 ведущий режим буферизации;
бит 4 0 последовательно,
1 специальный полный вложенный режим.
биты 7..5 равны нулю.
ПРИМЕЧАНИЕ: Управляющие слова инициализации загружаются последовалельно после передачи ICW1.
Управление операциями контроллера.
Команды управления операциями могут быть посланы контроллеру после инициализации в любой момент.
Порт 21h - OCW1 регистр маски прерываний (IMR)
биты 7..0 0 обслуживание прерывания,
1 маскирование прерывания;
Порт 20h - OCW2 регистр команд прерываний (ICR)
биты 2..0 определяют номер бита регистра текущего обслуживания (ISR),
биты 4..3 равны нулю (определяют OCW2),
бит 5 1 завершение прерывания;
бит 6 1 очистка указанного бита ISR;
бит 7 1 циклический сдвиг приоритетов.
Порт 20h - OCW3 слово управления операцией
биты 1..0 чтение регистра:
0 или 1 чтения нет,
2 читать IRR при следующем обращении,
3 читать ISR при следующем обращении;
бит 2 1 указание сформировать слово-состояния (содержит номер наивысшего запроса из поступивших);
биты 4..3 01 признак OCW3;
биты 6..5 специальное маскирование:
0 или 1 отсутствует,
2 отменяет,
3 устанавливает (при этом выравниваются приоритеты запросов);
бит 7 равен нулю.
Запрет/разрешение отдельных аппаратных прерываний.
Программы на асемблере могут запретить аппаратные прерывания. Это маскируемые прерывания; другие аппаратные прерывания, возникающие при некоторых ошибках (таких как деление на ноль) не могут быть маскированы.
Имеются две причины для запрета аппаратных прерываний.
В первом случае все прерывания блокируются с тем чтобы критическая часть кода была выполнена целиком, прежде чем машина произведет какое-либо другое действие. Например, прерывания запрещают при изменении вектора аппаратного прерывания, избегая выполнения прерывания когда вектор изменен только наполовину.
Во втором случае маскируются только определенные аппаратные прерывания. Это делается когда некоторые определенные прерывания могут взаимодействовать с операциями, критичными к временам. Например, точно рассчитанная по времени процедура ввода/вывода не может себе позволить быть прерванной длительным дисковым прерыванием.
Выполнение прерываний зависит от значения флага прерывания (бит 9) в регистре флагов. Когда этот бит равен 0, то разрешены все прерывания, которые разрешает маска. Когда он равен 1, то все аппаратные прерывания запрещены. Чтобы запретить прерывания, установив этот флаг в 1, используется инструкция CLI. Для очистки этого флага и восстановления прерываний - инструкция STI. Избегайте отключения прерываний на длительный период. Прерывание времени суток происходит 18.2 раза в секунду и если к этому прерыванию был более чем один запрос в то время, когда аппаратные прерывания были запрещены, то лишние запросы будут отброшены исистемное время будет определяться неправильно.
Машина автоматически запрещает аппаратные прерывания при вызове программных прерываний и автоматически разрешает их при возврате. Когда Вы пишете свои программные прерывания, то Вы можете начать программу с инструкции STI, если Вы можете допустить аппаратные прерывания. Однако если за инструкцией CLI не следует STI, то это приведет к остановке машины, так как ввод с клавиатуры будет заморожен.
Для маскирования определенных аппаратных прерываний нужно просто послать требуемую цепочку битов в порт с адресом 21H, который соответствует регистру маски прерываний (IMR). Регистр маски на второй микросхеме 8259 для AT (IRQ8-15) имеет адрес порта A1H. Необходимо установите те биты регистра, которые соответствуют номерам прерываний, которые Вы хотите маскировать.
Нижеприведенный пример блокирует дисковое прерывание. Не забудьте очистить регистр в конце программы, иначе обращение к дискам будет запрещено и после завершения программы.
;---маскирование 6-го бита регистра маски прерываний
MOV AL,01000000B ;маскируем бит 6
OUT 21H,AL ;посылаем в регистр маски прерываний
.
.
MOV AL,0 ;
OUT 21H,AL ;очищаем IMR в конце программы
В конце кода каждого из Ваших аппаратных прерываний Вы должны включить следующие 2 строчки кода:
MOV AL,20H
OUT 20H,AL
Если аппаратное прерывание не заканчивается этими строками, то микросхема 8259 не очистит информацию регистра обслуживания, с тем чтобы была разрешена обработка прерываний с более низкими уровнями, чем только что обработанное. Отсутствие этих строк легко может привести к краху программы, так как прерывания от клавиатуры скорее всего окажутся замороженными и даже Ctrl-Alt-Del окажется бесполезным. Эта добавка не нужна для тех векторов прерываний, которые являются расширениями существующих прерываний.