Для обработки асинхронных событий существует механизм прерываний, можно сказать, что прерывание - это событие, которое требует немедленной обработки. Можно написать обработку почти любого события (сигнал с датчика, нажатие клавиши, движение мышью и т.д.), например, некоторые системы повышенной надёжности, при отсутствии питания от сети начинают копировать данные на жёсткие диски, вот один из примеров использования прерываний.
С прерыванием связывают число, называемое номером прерывания. Программы могут использовать прерывания для получения возможности использования функкий BIOS или операционной системы, например, прерывание MS DOS с большим количеством различных функций имеет номер 21h и вызывается программно с помощью инструкции INT. Пример:
Код: Выделить всё
.286
.model tiny
code segment
org 100h
start:
mov ax, 4c00h ;номер функции передачи управления родительскому процессу (программе, которая запустила
int 21h ;выполнение данной программы) и вызов программного прерывания
code ends
end start
Составление собственных программ обработки прерываний требует повышенной внимательности и понимания всех тонкостей работы аппаратуры и взаимодействия программного и аппаратного обеспечения. При отладке возможно "разрушение" важных областей памяти, поэтому надо следить за тем, что делает ваша программа.
Для связи обработчика прерывания с номером прерывания существует таблица прерываний, расположенная по адресу 0000:0000 и до 0000:03FFh, таблица содержит 256 элементов по 4 байта (смещение и сегмент обработчика прерываний), эти адреса называют векторами прерываний.
Таблица прерываний инициализируется частично BIOS, а частично операционной системой при загрузке, также операционная система может "переключить" на себя некоторые прерывания BIOS.
Теперь приведу вид таблицы прерываний после загрузки операционной системы MS DOS:
0 Ошибка деления. Вызывается автоматически после выполнения команд DIV или IDIV, если в результате деления происходит переполнение (например, при делении на 0). DOS обычно при обработке этого прерывания выводит сообщение об ошибке и останавливает выполнение программы. Для процессора 8086 при этом адрес возврата указывает на следующую после команды деления команду, а в процессоре 80286 - на первый байт команды, вызвавшей прерывание.
1 Прерывание пошагового режима. Вырабатывается после выполнения каждой машинной команды, если в слове флагов установлен бит пошаговой трассировки TF. Используется для отладки программ. Это прерывание не вырабатывается после выполнения команды MOV в сегментные регистры или после загрузки сегментных регистров командой POP.
2 Аппаратное немаскируемое прерывание. Это прерывание может использоваться по-разному в разных машинах. Обычно вырабатывается при ошибке четности в оперативной памяти и при запросе прерывания от сопроцессора.
3 Прерывание для трассировки. Это прерывание генерируется при выполнении однобайтовой машинной команды с кодом CCh и обычно используется отладчиками для установки точки прерывания.
4 Переполнение. Генерируется машинной командой INTO, если установлен флаг OF. Если флаг не установлен, то команда INTO выполняется как NOP. Это прерывание используется для обработки ошибок при выполнении арифметических операций.
5 Печать копии экрана. Генерируется при нажатии на клавиатуре клавиши PrtScr. Обычно используется для печати образа экрана. Для процессора 80286 генерируется при выполнении машинной команды BOUND, если проверяемое значение вышло за пределы заданного диапазона.
6 Неопределенный код операции или длина команды больше 10 байт (для процессора 80286).
7 Особый случай отсутствия математического сопроцессора (процессор 80286).
8 IRQ0 - прерывание интервального таймера, возникает 18,2 раза в секунду.
9 IRQ1 - прерывание от клавиатуры. Генерируется при нажатии и при отжатии клавиши. Используется для чтения данных от клавиатуры.
A IRQ2 - используется для каскадирования аппаратных прерываний в машинах класса AT.
B IRQ3 - прерывание асинхронного порта COM2.
C IRQ4 - прерывание асинхронного порта COM1.
D IRQ5 - прерывание от контроллера жесткого диска для XT.
E IRQ6 - прерывание генерируется контроллером флоппи-диска после завершения операции.
F IRQ7 - прерывание принтера. Генерируется принтером, когда он готов к выполнению очередной операции. Многие адаптеры принтера не используют это прерывание.
10 Обслуживание видеоадаптера.
11 Определение конфигурации устройств в системе.
12 Определение размера оперативной памяти в системе.
13 Обслуживание дисковой системы.
14 Последовательный ввод/вывод.
15 Расширенный сервис для AT-компьютеров.
16 Обслуживание клавиатуры.
17 Обслуживание принтера.
18 Запуск BASIC в ПЗУ, если он есть.
19 Загрузка операционной системы.
1A Обслуживание часов.
1B Обработчик прерывания Ctrl-Break.
1C Прерывание возникает 18.2 раза в секунду, вызывается программно обработчиком прерывания таймера.
1D Адрес видеотаблицы для контроллера видеоадаптера 6845.
1E Указатель на таблицу параметров дискеты.
1F Указатель на графическую таблицу для символов с кодами ASCII 128-255.
20-5F Используется DOS или зарезервировано для DOS.
60-67 Прерывания, зарезервированные для пользователя.
68-6F Не используются.
70 IRQ8 - прерывание от часов реального времени.
71 IRQ9 - прерывание от контроллера EGA.
72 IRQ10 - зарезервировано.
73 IRQ11 - зарезервировано.
74 IRQ12 - зарезервировано.
75 IRQ13 - прерывание от математического сопроцессора.
76 IRQ14 - прерывание от контроллера жесткого диска.
77 IRQ15 - зарезервировано.
78 - 7F Не используются.
80-85 Зарезервированы для BASIC.
86-F0 Используются интерпретатором BASIC.
F1-FF Не используются.
IRQ0-IRQ15 это аппаратные прерывания, о них будет рассказано ниже.
В критических участках программы, чтобы гарантированно выполнить определённую последовательность действий, часто запрещают прерывания, сделать это можно инструкцией CLI, нужно выполнить инструкцию CLI перед критическим участком программы, а затем разрешить прерывания инструкцией STI. Необходимо следить за тем, чтобы прерывания не были запрещены слишком долго, это может отразиться на работе компьютера (например, будут отставать часы, так как это тоже прерывание от системного таймера).
Если надо запретить не все прерывания, а только некоторые, тогда придётся использовать возможности контроллера прерываний и маскировать нужные нам прерывания. Процесс запрета прерываний от некоторых устройств называется маскированием прерываний, т.к. контроллер прерываний имеет несколько регистров, регистр запроса, куда поступает запрос на прерывание, регистр маски, он как раз и отвечает за маскирование прерываний, чтобы запретить прерывание, необходимо записать в определённый бит регистра, соответствующий входу (IRQ0-IRQ7) логическую 1.
Механизм обработки прерываний таков, поступающие прерывания запоминаются в регистре запроса на прерывание IRR. Каждый бит из восьми в этом регистре соответствует прерыванию. После проверки на обработку в настоящий момент другого прерывания запрашивается информация из регистра обслуживания ISR. Перед выдачей запроса на прерывание в процессор проверяется содержимое восьмибитового регистра маски прерываний IMR. Если прерывание данного уровня не замаскировано, то выдается запрос на прерывание.
Нужно отметить, что номера входов контроллера, на которые поступает запрос на прерывание не соответствуют номеру программы - обработчика прерывания, например, запрос на прерывание клавиатуры приходит на вход контроллера IRQ1, а номер обработчика прерывания в таблице прерываний 9.
Иногда программе может потребоваться заменить обработчик прерывания на свой, для этого программа должна переназначить вектор прерывания (изменить адрес в таблице на адрес своей программы), важно после выполнения программы восстановить старый адрес обработчика прерываний, т.к. ОС будет считать, что область памяти свободна и записать туда что-то другое, "испортив" при этом обработчик прерывания.
Также важно запретить прерывания перед заменой вектора, а затем снова разрешить, ведь прерывание может произойти в момент замены вектора прерываний, например, успев заменить лишь смещение и не изменив сегмент, выполнится "что-то" из другой области памяти, но только не ваша программа.
Последовательность действий для нерезидентных программ, обрабатывающих прерывания:
- прочитать содержимое элемента таблицы векторов прерываний для вектора с нужным вам номером;
- запомнить это содержимое (адрес старого обработчика прерывания) в области данных программы;
- установить новый адрес в таблице векторов прерываний так, чтобы он соответствовал началу Вашей программы обработки прерывания;
- перед завершением работы программы прочитать из области данных адрес старого обработчика прерывания и записать его в таблицу векторов прерываний.
Функции DOS для работы с таблицей прерываний:
- Для чтения вектора используйте функцию 35h прерывания 21h. Перед ее вызовом регистр AL должен содержать номер вектора в таблице. После выполнения функции в регистрах ES:BX будет искомый адрес обработчика прерывания.
- Функция 25h прерывания 21h устанавливает для вектора с номером, находящимся в AL, обработчик прерывания DS:DX.
Приведу таблицу аппаратных прерываний, расположенных в порядке приоритета по убыванию (самое первое прерывание в таблице имеет наивысший приоритет), а число в левом столбце соответствует номеру обработчика прерываний (номер вектора в таблице прерываний):
8 IRQ0 прерывание интервального таймера, возникает 18,2 раза в секунду.
9 IRQ1 прерывание от клавиатуры. Генерируется при нажатии и при отжатии клавиши. Используется для чтения данных с клавиатуры.
A IRQ2 используется для каскадирования аппаратных прерываний в машинах класса AT.
70 IRQ8 прерывание от часов реального времени.
71 IRQ9 прерывание от контроллера EGA.
72 IRQ10 зарезервировано.
73 IRQ11 зарезервировано.
74 IRQ12 зарезервировано.
75 IRQ13 прерывание от математического сопроцессора.
76 IRQ14 прерывание от контроллера жесткого диска.
77 IRQ15 зарезервировано.
B IRQ3 прерывание асинхронного порта COM2.
C IRQ4 прерывание асинхронного порта COM1.
D IRQ5 прерывание от контроллера жесткого диска для XT.
E IRQ6 прерывание генерируется контроллером флоппи диска после завершения операции
F IRQ7 прерывание принтера. Генерируется принтером, когда он готов к выполнению очередной операции. Многие адаптеры принтера не используют это прерывание.
Выше я описал механизм прерываний, отмечу, что наиболее интересными для программирования являются регистр маски IMR, который имеет порт с адресом 21h, а также управляющий регистр, который имеет порт с адресом 20h.
Вообще контроллера прерываний 2 (master и slave), ведомый контроллер подключен ко входу IRQ2 ведущего контроллера. Регистр маски прерываний второго контроллера имеет адрес A1h, управляющий регистр прерываний - A0h.
Разряды 8-битного регистра маски соответствуют номерам IRQ. Для того, чтобы замаскировать аппаратное прерывание, надо записать в регистр байт, в котором бит с номером, соответствующим входу IRQ будет установлен в 1. Например, для маскирования прерываний от клавиатуры необходимо записать в порт 21h байт со значением 00000010b.
Давайте запретим прерывания от клавиатуры:
Код: Выделить всё
.model tiny
.286
code segment
org 100h
start:
mov al, 00000010b
out 21h, al
mov ax, 4c00h
int 21h
code ends
end start
Давайте теперь заменим обработчик прерывания клавиатуры на свою программу, которая при каждом нажатии клавиши будет выводить на экран букву А в левом верхнем углу:
Код: Выделить всё
.model tiny
.286
code segment
org 100h
start:
jmp init
new_int:
push bx
push es
push 0b800h
pop es
xor bx, bx
mov byte ptr es:[bx+160d], 41h
pop es
pop bx
jmp dword ptr[old_int]
old_int dw ?
dw ?
init:
mov ah, 35h
mov al, 9d ;get interrupt vector
int 21h
mov word ptr old_int, bx ;save old vector
mov word ptr old_int+2, es
mov ax, 2509h
mov dx, offset new_int ;set new vector
int 21h
mov ax, 3100h
mov dx, sz
int 21h
mov ax, 4c00h
int 21h
sz equ (init-new_int+10Fh)/16d
code ends
end start
Была использована версия компилятора MASM 6.11 в контексте операционной системы MS DOS 6.22!
Спасибо за внимание!
С уважением, push0ret!