Иллюстрированный самоучитель по Assembler

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

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

Пусть наш обработчик в ответ на каждое прерывание от таймера выводит на экран какой-нибудь символ. Для этого можно воспользоваться функцией 0Eh прерывания BIOS 10h. Это прерывание обслуживает большое количество различных функций, обеспечивающих управление экраном. Сюда входят функции вывода символов и строк, настройки режимов видеосистемы, загрузки нестандартных таблиц символов и многие другие. Функция 0Eh предназначена для вывода на экран отдельных символов. Она требует указания в регистре AL кода выводимого символа. Процедура new_08 будет выглядеть в этом случае следующим образом:

; Обработчик прерываний для примера 3.3
new_08 proc
push AX; Сохраним исходное значение AX
mov AH,0Eh; Функция вывода символа
mov AL,'@'; Выводимый символ
int 10 h; Переход в BIOS
mov AL,20h; Разблокировка прерываний
out 20h,AL; в контроллере прерываний
pop AX; Восстановим AX
iret; Возврат в прерванную программу
new_08 endp

Что же касается основной программы, то самое простое включить в нее (после завершения действий по инициализации обработчика прерываний) функцию DOS 0 Hi ожидания ввода с клавиатуры:

mov AH,01h
int 21h

В результате программа, дойдя до этих строк, остановится (фактически будет выполняться цикл опроса клавиатуры в ожидании нажатия клавиши, включенный в состав программы реализации функции 01h DOS), а на экран непрерывной чередой будут выводиться символы коммерческого at (рис. 3.4). После нажатия на любую клавишу программа завершится.

Иллюстрированный самоучитель по Assembler › Команды и алгоритмы › Обработчики аппаратных прерываний. Обработчики программных прерываний.
Рис. 3.4. Вывод программы 3.3

Приведенный пример позволяет обсудить чрезвычайно важный вопрос о взаимодействии обработчиков аппаратных прерываний с прерываемой программой и операционной системой. Особенностью аппаратных прерываний является то, что они могут возникнуть в любой момент времени и, соответственно, прервать выполняемую программу в любой точке. Текущая программа, разумеется, использует регистры, как общего назначения, так и сегментные. Если в обработчике прерывания мы разрушим содержимое хотя бы одного из регистров процессора, прерванная программа по меньшей мере продолжит свое выполнение неправильным образом, а скорее всего произойдет зависание системы.

Поэтому в любом обработчике аппаратных прерываний необходимо в самом его начале сохранить все регистры, которые будут использоваться в программе обработчика, а перед завершением обработчика (перед командой iret) восстановить их. Регистры, которые обработчиком не используются, сохранять не обязательно.

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

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

В нашем случае дело усугубляется тем, что прерывания от таймера не только могут придти в тот момент, когда выполняется функция DOS, но и неминуемо приходят только в такие моменты, так как мы остановили программу с помощью вызова функции 01h прерывания 2Hi и, следовательно, все время, пока наша программа ждет нажатия клавиши, в действительности выполняются внутренние программы DOS. Именно поэтому мы отказались от использования в обработчике прерывания функции DOS и выводим на экран символы с помощью прерывания BIOS. Выполнение функции BIOS "на фоне" DOS не так опасно. Надо только следить за тем, чтобы наше прерывание BIOS в обработчике не оказалось вложенным в такое же прерывание BIOS в прерываемой программе.

Рассмотренный пример имеет существенный недостаток. Записав в вектор прерываний 8 адрес нашего обработчика, мы затерли исходное содержимое вектора и тем самым ликвидировали (в логическом плане) исходный, системный обработчик. Практически это приведет к тому, что на время работы нашей программы остановятся системные часы, и если в системе есть какие-то другие программы, использующие прерывания от таймера, они перестанут работать должным образом. Ликвидировать указанный недостаток очень просто: надо "сцепить" наш обработчик с системным так, чтобы в ответ на каждый сигнал прерывания активизировались последовательно оба обработчика. Рассмотрим методику сцепления обработчиков.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.