Программирование аппаратных средств
Действия, которые должны инициироваться нажатием левой или правой клавиш мыши (например, включение или выключение некоторого оборудования), в программе заменены выводом на экран коротких диагностических сообщений. Вывод осуществляется прямой записью в видеобуфер, поскольку, как уже говорилось ранее, в обработчике аппаратных прерываний нельзя использовать функции DOS и рискованно – функции BIOS. Вывод на экран с помощью команд обработки строк lodsb и stosw требует настройки большого количества регистров – в DS:SI должен находиться адрес строки-источника, в ES:DI адрес позиции в видеобуфере, в СХ число выводимых символов. Кроме этого, в обработчике прерываний используются регистры АХ, ВХ и DX. Для сохранения всех регистров общего назначения используется команда pusha, а для их восстановления команда рора. Однако эти команды не принимают в расчет сегментные регистры, и их приходится сохранять и восстанавливать от дельными командами.
С восстановлением регистров может возникнуть некоторая сложность. Обработчик прерывания должен завершаться посылкой в контроллер прерываний команды EOI, а для этого необходим регистр AL. Поэтому восстановление регистров, во всяком случае, регистра АХ, необходимо выполнять после команды EOI. С другой стороны, команда EOI разблокирует нижележащие уровни прерываний в контроллере прерываний (см. гл. 3), что может привести к прохождению через контроллер очередного (вложенного в наше) прерывания, которое прервет наш обработчик в точке, где еще не восстановлены регистры. Это неминуемо приведет к краху системы. Однако в процессоре предусмотрены меры устранения этого неприятного явления. Остановимся на них более подробно.
Процессор, приняв любой сигнал прерывания, сбрасывает флаг IF в своем регистре флагов, запрещая тем самым все аппаратные прерывания. Поэтому вход в обработчик прерываний всегда осуществляется при запрещенных прерываниях. Блокировка нижележащих уровней в контроллере прерываний просто накладывается на этот общий запрет и новых ограничений не вносит.
Если в тексте обработчике прерываний нет команды разрешения прерываний sti, то прерывания будут запрещены до самого его конца, до завершающей команды iret. Эта команда извлекает из стека и восстанавливает исходное содержимое регистров CS:IP, а также регистра флагов. В момент прерывания в регистре флагов был безусловно установлен флаг IF, иначе прерывание не могло бы возникнуть. Восстановление регистра флагов приводит к установке этого флага и разрешению всех аппаратных прерываний, но уже после завершения обработчика прерываний. Таким образом, снятие аппаратной блокировки прерываний командой EOI в действительности не приводит к разрешению прерываний, и любые строки, стоящие после этой команды, выполняются при запрещенных прерываниях. В результате никаких проблем с восстановлением регистров после команды EOI не возникает.
Обычно, однако, используется другой вариант построения обработчика прерываний. В этом варианте в начале программы обработчика выполняется команда sti, устанавливающая флаг IF и разрешающая все аппаратные прерывания, кроме тех, которые заблокированы в контроллере прерываний. В результате программа обработчика может быть прервана любым прерыванием более высокого уровня IRQ (т.е. уровня с меньшим номером), но не прерывается сигналами прерываний этого же и более низких уровней. Такое построение обработчиков прерываний удобно тем, что "более важные" прерывания, например, от таймера или клавиатуры, могут быть обработаны без задержки.
Для того, чтобы исключить возможные неприятности с восстановлением регистра АХ после команды EOI, перед ней прерывания запрещаются командой cli и структура обработчика прерываний приобретает приблизительно такой вид:
sti pusha; Сохранение регистров …; Тело обработчика cli; Запрещение всех прерываний mov AL,20h; Команда EOI out 20h,AL; контроллеру прерываний рора; Восстановление регистров iret; Возврат из обработчика
Команды рора и iret выполняются в этому случае при запрещенных прерываниях, но после отработки команды iret в регистре флагов восстанавливается его исходное содержимое (в котором IF = 1), и прерывания, таким образом, снова разрешаются.