[Назад] [Далее]

5.10.10. Контроллер прерываний

Контроллер прерываний — устройство, которое получает запросы на аппаратные прерывания от всех внешних устройств. Он определяет, какие запросы следует обслужить, какие должны ждать своей очереди, а какие не будут обслуживаться вообще. Контроллеров прерываний, так же как и контроллеров DMA, два. Первый контроллер, обслуживающий запросы на прерывания от IRQ0 до IRQ7, управляется через порты 20h и 21h, а второй (IRQ8 – IRQ15) — через порты A0h и A1h.

Команды контроллеру делят на команды управления (OCW) и инициализации (ICW):

Команды управления

OCW1:

При помощи этой команды можно временно запретить или разрешить то или иное аппаратное прерывание. Например, команды

        in         al,21h
        or         al,00000010b
        out        21h,al

приводят к отключению IRQ1, то есть клавиатуры.

Мы пользовались OCW1 в программе term2.asm, чтобы разрешить IRQ3 — прерывание от последовательного порта COM2.


OCW2: команды конца прерывания и сдвига приоритетов

Как упоминалось в главе 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: чтение состояния контроллера и режим специального маскирования

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

Чаще всего OCW3 используют для чтения состояния контроллера — младшие два бита выбирают, какой из регистров контроллера будет возвращаться при последующем чтении из порта 21h/A1h. Оба возвращаемых регистра имеют структуру, аналогичную OCW1, — каждый бит отвечает соответствующему IRQ.

Из регистра запросов на прерывания можно узнать, какие прерывания произошли, но пока не были обработаны, а из регистра обслуживаемых прерываний — какие прерывания обрабатываются в данный момент. Последнее — еще одна мера безопасности, которую применяют резидентные программы, — нельзя работать с дисководом (IRQ6), если в этот момент обслуживается прерывание от последовательного порта (IRQ3), и нельзя работать с диском (IRQ14/15), если обслуживается прерывание от системного таймера (IRQ0).

Команды инициализации

Чтобы инициализировать контроллер, BIOS посылает последовательность из команды ICW1 в порт 20h/A0h (она отличается от OCW своим битом 4) и трех команд инициализации ICW2, ICW3, ICW4 в порт 21h/ A1h сразу после этого.

Повторив процедуру инициализации, программа может, например, изменить соответствие между обработчиками прерываний и реальными аппаратными прерываниями. Переместив базовый адрес первого контроллера на неиспользуемую область (например, 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

п»ї
"target=_blank><\/a>") //-->