[Назад] [Далее] | |
Контроллер прерываний — устройство, которое получает запросы на аппаратные прерывания от всех внешних устройств. Он определяет, какие запросы следует обслужить, какие должны ждать своей очереди, а какие не будут обслуживаться вообще. Контроллеров прерываний, так же как и контроллеров DMA, два. Первый контроллер, обслуживающий запросы на прерывания от IRQ0 до IRQ7, управляется через порты 20h и 21h, а второй (IRQ8 – IRQ15) — через порты A0h и A1h.
Команды контроллеру делят на команды управления (OCW) и инициализации (ICW):
порт 20h/A0h для записи: OCW2, OCW3, ICW1
порт 20h/A0h для чтения — см. команду OCW3
порт 21h/A1h для чтения и записи: OCW1 — маскирование прерываний
порт 21h/A1h для записи — ICW2, ICW3, ICW4 сразу после ICW1
OCW1:
биты 7 – 0: прерывание 7 – 0/15 – 8 запрещено
При помощи этой команды можно временно запретить или разрешить то или иное аппаратное прерывание. Например, команды
in al,21h or al,00000010b out 21h,al
приводят к отключению IRQ1, то есть клавиатуры.
Мы пользовались OCW1 в программе term2.asm, чтобы разрешить IRQ3 — прерывание от последовательного порта COM2.
OCW2: команды конца прерывания и сдвига приоритетов
биты 7 – 5: команда
000: запрещение сдвига приоритетов в режиме без EOI
001: неспецифичный EOI (конец прерывания в режиме с приоритетами)
010: нет операции
011: специфичный EOI (конец прерывания в режиме без приоритетов)
100: разрешение сдвига приоритетов в режиме без EOI
101: сдвиг приоритетов с неспецифичным EOI
110: сдвиг приоритетов
111: сдвиг приоритетов со специфичным EOI
биты 4 – 3: 00 (указывают, что это OCW2)
биты 2 – 0: номер IRQ для команд 011lb, 110 и 111
Как упоминалось в главе 5.8.2, если несколько прерываний происходят одновременно, обслуживается в первую очередь то, которое имеет высший приоритет. При инициализации контроллера высший приоритет имеет IRQ0 (прерывание от системного таймера), а низший — IRQ7. Все прерывания второго контроллера (IRQ8 – IRQ15) оказываются в этой последовательности между IRQ1 и IRQ3, так как именно IRQ2 используется для каскадирования этих двух контроллеров. Команды сдвига приоритетов позволяют изменить эту ситуацию, присвоив завершающемуся (команды 101 или 111) или обрабатывающемуся (110) прерыванию низший приоритет, причем следующее прерывание получит наивысший, и далее по кругу.
Более того, в тот момент, когда выполняется обработчик аппаратного прерывания, другие прерывания с низшими приоритетами не происходят, даже если обработчик выполнил команду sti. Чтобы разрешить выполнение других прерываний, каждый обработчик обязательно должен послать команду EOI — конец прерывания — в соответствующий контроллер. Именно поэтому обработчики аппаратных прерываний в программах term2.asm и wavdma.asm заканчивались командами
mov al,20h ; команда "неспецифичный конец прерывания" out 20h,al ; посылается в первый контроллер прерываний
Если бы контроллер был инициализирован в режиме без приоритетов, вместо неспецифичного EOI пришлось бы посылать специфичный, содержащий в младших трех битах номер прерывания, но BIOS инициализирует контроллер именно в режиме с приоритетами. Кроме того, контроллер мог бы быть инициализирован в режиме без EOI, но тогда в ходе работы обработчика прерывания могли бы происходить все остальные прерывания, включая обрабатываемое. О способах инициализации контроллера говорится далее, а здесь рассмотрим последнюю команду управления.
OCW3: чтение состояния контроллера и режим специального маскирования
бит 7: 0
биты 6 – 5: режим специального маскирования
00 — не изменять
10 — выключить
11 — включить
биты 4 – 3: 01 — указывает, что это OCW3
бит 2: режим опроса
биты 1 – 0: чтение состояния контроллера
00 — не читать
10 — читать регистр запросов на прерывания
11 — читать регистр обслуживаемых прерываний
В режиме специального маскирования в момент выполнения обработчика прерывания разрешены все прерывания, кроме выполняющегося и маскируемых командой OCW1, что имеет смысл сделать, если обработчик прерывания с достаточно высоким приоритетом собирается выполняться слишком долго.
Чаще всего OCW3 используют для чтения состояния контроллера — младшие два бита выбирают, какой из регистров контроллера будет возвращаться при последующем чтении из порта 21h/A1h. Оба возвращаемых регистра имеют структуру, аналогичную OCW1, — каждый бит отвечает соответствующему IRQ.
Из регистра запросов на прерывания можно узнать, какие прерывания произошли, но пока не были обработаны, а из регистра обслуживаемых прерываний — какие прерывания обрабатываются в данный момент. Последнее — еще одна мера безопасности, которую применяют резидентные программы, — нельзя работать с дисководом (IRQ6), если в этот момент обслуживается прерывание от последовательного порта (IRQ3), и нельзя работать с диском (IRQ14/15), если обслуживается прерывание от системного таймера (IRQ0).
Чтобы инициализировать контроллер, BIOS посылает последовательность из команды ICW1 в порт 20h/A0h (она отличается от OCW своим битом 4) и трех команд инициализации ICW2, ICW3, ICW4 в порт 21h/ A1h сразу после этого.
ICW1:
биты 7 – 4: 0001
бит 3: 1/0 — срабатывание по уровню/фронту сигнала IRQ (принято 0)
бит 2: 1/0 — размер вектора прерывания 4 байта/8 байт (1 для 80x86)
бит 1: каскадирования нет, ICW3 не будет послано
бит 0: ICW4 будет послано
ICW2:
номер обработчика прерывания для IRQ0/IRQ8 (кратный восьми) (08h — для первого контроллера, 70h — для второго. Некоторые операционные системы изменяют первый обработчик на 50h)
ICW3 для ведущего контроллера:
биты 7 – 0: к выходу 7 – 0 присоединен подчиненный контроллер (0100b в PC)
ICW3 для подчиненного контроллера:
биты 3 – 0: номер выхода ведущего контроллера, к которому подсоединен ведомый
ICW4:
биты 7 – 5: 0
бит 4: контроллер в режиме фиксированных приоритетов
биты 3 – 2: режим:
00, 01 — небуферированный
10 — буферированный/подчиненный
11 — буферированный/ведущий
бит 1: режим с автоматическим EOI (то есть обработчикам не надо посылать EOI в контроллер)
бит 0: 0 — режим совместимости с 8085, 1 — обычный
Повторив процедуру инициализации, программа может, например, изменить соответствие между обработчиками прерываний и реальными аппаратными прерываниями. Переместив базовый адрес первого контроллера на неиспользуемую область (например, 50h) и установив собственные обработчики на каждое из прерываний INT 50h – 58h, вызывающие обработчики INT 08h – 0Fh, вы сможете быть абсолютно уверены, что никакая программа не установит обработчик аппаратного прерывания, который получил бы управление раньше вашего.
; picinit.asm ; Выполняет полную инициализацию обоих контроллеров прерываний ; с отображением прерываний IRQ0 - IRQ7 на векторы INT 50h - 57h. ; Программа остается резидентной и издает короткий звук после каждого IRQ1. ; Восстановление старых обработчиков прерываний и переинициализация ; контроллера в прежнее состояние опущены .model tiny .code org 100h ; СОМ-программа PIC1_BASE equ 50h ; на этот адрес процедура pic_init ; перенесет IRQ0 - IRQ7 PIC2_BASE equ 70h ; на этот адрес процедура pic_init ; перенесет IRQ8 - IRQ15 start: jmp end_of_resident ; переход на начало инсталляционной части irq0_handler: ; обработчик IRQ0 ; (прерывания от системного таймера) push ax in al,61h and al,11111100b ; выключение динамика out 61h,al pop ax int 08h ; старый обработчик IRQ0 iret ; он послал EOI, так что завершить ; простым iret irq1_handler: ; обработчик IRQ1 push ax ; (прерывание от клавиатуры) in al,61h or al,00000011b ; включение динамика out 61h,al pop ax int 09h ; старый обработчик IRQ1 iret irq2_handler: ; и так далее int 0Ah iret irq3_handler: int 0Bh iret irq4_handler: int 0Ch iret irq5_handler: int 0Dh iret irq6_handler: int 0Eh iret irq7_handler: int 0Fh iret end_of_resident: ; конец резидентной части call hook_pid_ints ; установка наших обработчиков call init_pic ; переинициализация контроллера прерываний mov dx,offset end_of_resident int 27h ; оставить наши новые обработчики ; резидентными ; процедура init_pic ; выполняет инициализацию обоих контроллеров прерываний, ; отображая IRQ0 - IRQ7 на PIC1_BASE - PIC1_BASE+7, ; a IRQ8 - IRQ15 на PIC2_BASE - PIC2_BASE+7 ; для возврата в стандартное состояние вызвать с ; PIC1_BASE = 08h ; PIC2_BASE = 70h init_picproc near cli mov al,00010101b ; ICW1 out 20h,al out 0A0h,al mov al,PIC1_BASE ; ICW2 для первого контроллера out 2lh,al mov al,PIC2_BASE ; ICW2 для второго контроллера out 0A1h,al mov al,04h ; ICW.3 для первого контроллера out 21h,al mov al,02h ; ICW3 для второго контроллера out 0A1h,al mov al,00001101b ; ICW4 для первого контроллера out 21h,al mov al,00001001b ; ICW4 для второго контроллера out 0A1h,al sti ret init_pic endp ; перехват прерываний от PIC1_BASE до PIC1_BASE+7 hook_pic1_ints proc near mov ax,2500h+PIC1_BASE mov dx,offset irq0_handler int 21h mov ax,2501h+PIC1_BASE mov dx,offset irq1_handler int 21h mov ax,2502h+PIC1_BASE mov dx,offset irq2_handler int 21h mov ax,2503h+PIC1_BASE mov dx,offset irq3_handler int 21h mov ax,2504h+PIC1_BASE mov dx,offset irq4_handler int 21h mov ax,2505h+PIC1_BASE mov dx,offset irq5_handler int 21h mov ax,2506h+PIC1_BASE mov dx,offset irq6_handler int 21h mov ax,2507h+PIC1_BASE mov dx,offset irq7_handler int 21h ret hook_pic1_ints endp end start