Системное программное обеспечение персональных ЭВМ

         

Перехват прерываний


3.3. Перехват прерываний

Пусть функция обработки прерывания у нас уже разработана, теперь следует обеспечить ее вызов. Вспомним, что механизм прерываний ПЭВМ работает следующим образом. При поступлении прерывания с номером NN в стеке запоминаются регистр флагов и регистры CS:IP, а из оперативной памяти по адресу NN*4 выбирается четырехбайтный адрес, по которому передается управление. Этот адрес называется вектором прерывания, а первые 1024 байт оперативной памяти - таблицей векторов прерываний. Вектор хранится в памяти в следующем порядке: младший байт смещения - старший байт смещения - младший байт сегмента - старший байт сегмента. Таким образом, если мы хотим, чтобы по прерыванию NN получала управление наша interrupt-функция, мы должны записать ее адрес на место вектора NN. Технику этой записи мы рассмотрим здесь же, но чуть ниже, а прежде обсудим некоторые проблемы, которые могут при этом возникнуть.

До нашего вмешательства по адресу вектора NN находился адрес системной (например, из состава BIOS) программы обработки прерывания NN. После того как мы запишем на его место адрес своей программы обработки прерывания, по прерыванию NN управление будет передаваться нашей interrupt-функции (отсюда и выражение - "перехват прерывания"). Но, возможно, те действия, которые выполнял системный обработчик прерывания NN были не лишними, а может быть, и жизненно необходимыми для функционирования системы. Чтобы не дублировать эти действия в своем обработчике прерывания (тем более, что мы не всегда можем иметь о них исчерпывающую информацию), необходимо прежде, чем записывать свой адрес на место вектора, сохранить где-то тот адрес, который там был записан (адрес системного обработчика). Первым (после сохранения регистров) действием нашего обработчика должна быть передача управления по этому адресу, то есть вызов системного обработчика прерывания. Такой подход в некоторых источниках называется "дополнением прерывания". Кстати, в этом случае мы можем не сбрасывать контроллер прерываний, так как эта операция выполняется системным обработчиком.
Когда программа, включающая в себя пользовательскую обработку прерывания, заканчивается, она должна восстановить значение перехваченного вектора, то есть, системную обработку прерывания.
При программировании на языке Ассемблера возникает трудность, связанная с вызовом системного обработчика. Возврат из системного обработчика производится командой IRET, следовательно, вызывать его просто командой CALL нельзя (для IRET в стеке должно быть три слова, а CALL записывает в стек только два). В некоторых источниках почему-то рекомендуется сохранять старый вектор также в таблице векторов на каком-либо свободном ее месте и вызывать старый обработчик командой INT. Проще, однако, перед выполнением команды CALL занести в стек содержимое регистра флагов (PUSHF), что и обеспечивает Турбо-Си для вызовов функций, имеющих описатель interrupt.
Рассмотренный подход дополнения прерываний можно легко распространить на случай, когда несколько одновременно находящихся в ОЗУ программ используют одно и то же прерывание. Этот случай иллюстрируется Рисунок 3.1.


Содержание раздела