§ Аппаратные прерывания

В режиме реальных адресов принято отображать аппаратные прерывания на фиксированные вектора: IRQ 0..7 - на вектора прерываний 8..0Fh, IRQ 8..15 - на 70h..7Fh. При работе в защищённом режиме такая схема работы IRQ нам не подходит, т.к. вектора 8..0Fh заняты исключениями. В связи с этим возникает необходимость при установке системы прерываний в защищённом режиме перенаправить аппаратные прерывания на другие вектора, лежащие за пределами 00..1Fh, а при возврате в режим реальных адресов - обратно, на 8..0F и 70h..7Fh.
Обработкой аппаратных прерываних в процессорах Intel386 и Intel486 занимается микросхема 8259A, а в Pentium и старше - продвинутый программируемый контроллер прерываний APIC (Advanced Programmable Interrupt Controller). Программирование APIC-а - это отдельная тема, а так как в этом разделе мы рассматриваем установку системы прерываний в защищённом режиме, то программировать APIC не будем. APIC обладает замечательным свойством - его можно отключить или, другими словами, запретить (disable) и тогда он будет эмулировать работу внешнего контроллера прерываний 8259A. Этим мы и воспользуемся.
APIC есть только в процессорах, начиная с Pentium, да и то не у всех, поэтому возникает необходимость обнаружения APIC в процессоре. В начале нашего примера будет сделан вызов на процедуру "what_cpu", которая выполнит следующее:
  • Не допустит выполнение программы, если процессор не 32-разрядный (i286 или XT).
  • Произведёт поиск локального APIC в процессоре и если обнаружит его, то установит переменную db APIC_presence в 1, иначе - в 0.
Текст этой процедуры здесь не приводится, т.к. обнаружение APIC затрагивает другие темы, которые здесь не обсуждаются - определение типа процессора и команда CPUID; по этой же причине, комментарии в самой процедуре минимальны. Исходный текст "what_cpu" заложен внутри исходника примера, который будет приведен в конце следующей главы.
Программирование контроллера прерываний также является отдельной темой, поэтому комментарии и здесь минимальны. Пока просто используйте эти "магические" действия:
  • Процедура P_Mode_redirect_IRQ отключает APIC, по мере необходимости и перенаправляет прерывания IRQ на вектора 20h..2Fh. Далее во всех наших примерах будет использоваться такая схема распределения векторов прерываний:
    00h..1Fh - исключения
    20h..2Fh - IRQ
    30h..FFh - программные прерывания
  • Процедура R_Mode_redirect_IRQ используется перед возвратом в R-Mode, она восстанавливает вектора прерываний IRQ.
  • Процедура redirect_IRQ используется обеими вышеприведенными процедурами, её прообраз взят из BIOS-а и слегка модифицирован для наших примеров.
  • Процедура disable_APIC запрещает APIC для правильной работы нашего примера, enable_APIC разрешает APIC только если он был включён.
Процедуры смотреть здесь.
1; BX = { BL = Начало для IRQ 0..7, BH = начало для IRQ 8..15 }
2; DX = Маска прерываний IRQ ( DL - для IRQ 0..7, DH - IRQ 8..15 )
3redirect_IRQ:
4
5	mov	al, 11h
6	out	0xA0, al
7	out	0x20, al
8
9    ; Вектора Master / Slave
10	mov	al, bh
11	out	0xA1, al
12	mov	al, bl
13	out	0x21, al
14
15	mov	al, 02
16	out	0xA1, al
17	mov	al, 04
18	out	0x21, al
19	mov	al, 01
20	out	0xA1, al
21	out	0x21, al
22
23    ; Маска прерываний
24	mov	al, dh
25	out	0xA1, al
26	mov	al, dl
27	out	0x21, al
28
29	ret