Подробное исследование работы клавиатуры ПК и обслуживающих ее прерываний, страница 6

А как же PIC 8259 узнает, что IRQ1 соответствует номер 9? Все дело в том, что PIC — программируемое устройство, и поэтому начальный код, выполняемый при загрузке компьютера, настраивает его нужным образом. Одним из действий, выполняемых при этом, будет настройка старших 5 бит байта, представляющего номер прерывания, передаваемого в ЦПУ. При формировании номера прерывания младшие 3 бита заполняются, номером IRQ. Таким образом можно адресовать 8 векторов от IRQ0 до IRQ7. Единственное неудобство здесь состоит в том, что обработчики аппаратных прерываний, подключенных к одному PIC, должны иметь смежные номера.

В IBM PC старшие 5 бит программируются в 00001В, что при дополнении 3 нулями дает номер обработчика таймерного прерывания (IRQ0). Таким образом, IRQ1, заполняя младшие 3 бита, составляет полный байт равный 00001001В или 09H. Восемь уровней IRQ проецируются на прерывания от INT 08H до INT OFH.

Очистка Программируемого Контроллера Прерываний обработчиком прерываний

Последнее, что должна выполнять программа обработки прерываний — это выдавать сообщение Программируемому Контроллеру Прерываний (PIC) об окончании прерывания. На ассемблере это выглядит так:

CLI        ; Запрет прерываний

MOV AL,20H ; Посылка неспецифичного конца

OUT 20H,AL ; прерывания EOI в порт 20Н

; Восстановление всех сохраненных

; регистров

IRET       ; Возврат в прерванную программу

Подробности приведены далее. Если имеются другие запросы IRQ, ожидающие обработки, то сразу после получения сигнала EOI, PIC посылает ЦПУ запрос на прерывание. Если прерывания разрешены, (любой хороший обработчик прерываний разрешает их, получив управление), то ЦПУ обратится к прерываниям. Это означает, что обработчик прерываний, заканчивающий работу, может быть прерван сразу после инструкции OUT (в нашем примере), до инструкции IRET. Это может показаться безопасным, однако результат будет катастрофическим, если такая ситуация повторится много раз подряд. Каждое дополнительное прерывание увеличивает стек на 6 байт плюс некоторый объем, используемый обработчиком прерываний для сохранения регистров. Многократное вложение прерываний означает неконтролируемый рост стека, что может привести к перезаписи (порче) информации в области данных или кода. В этом случае система будет испорчена.

Что же необходимо сделать для того, чтобы оказалось достаточно времени для выталкивания из стека сохраненных регистров, а также 6 байт (IP, CS, Flags) командой IRET. Для этого надо запрещать прерывания командой CLI непосредственно перед посылкой EOI в PIC. Разрешение прерываний будет выполнено командой IRET. Помимо восстановления CS и IP IRET восстанавливает содержимое регистра флагов и делает его таким, каким оно было до прерывания. Так как бит прерываний (бит, переключаемый инструкциями CLI и STI) в регистре флагов перед возникновением прерывания был установлен, то восстановление регистра прерываний разрешает прерывания. Стек будет очищен и далее спокойно смогут выполняться другие прерывания.

Для понимания того, что означает каждый бит байта 20Н, посылаемого в порт 20Н, необходимо заметить, что схема 8259А имеет много режимов работы, но в ПК она работает в режиме по умолчанию. В этом режиме IRQ выбираются в соответствии с фиксированными приоритетами. Чем меньше номер запроса IRQ, тем выше его приоритет. IRQ0, INT 08H (системный таймер) имеет наивысший приоритет. Запрос от клавиатуры IRQ1, INT 09H имеет второй уровень приоритета. Принтер (IRQ7, INT 0FH) имеет самый низкий приоритет. Прерывание с более низким приоритетом не может произойти во время обработки прерывания с более высоким приоритетом. Регистр обслуживания PIC (ISR) отслеживает, какое из прерываний обслуживается. В соответствии с этой логикой приоритетов PIC считает, что если получен сигнал EOI от обработчика прерываний, то нужно выбрать следующий по приоритету запрос и начать его обслуживать. Здесь заключена некоторая опасность, состоящая в том, что если послать лишний EOI, то он будет отнесен к следующему, еще не обрабатываемому запросу, который будет сброшен.