Глава 5. Аппаратные прерывания.
В режиме реальных адресов принято отображать аппаратные прерывания на фиксированные вектора: 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", которая выполнит следующее:
1. | Не допустит выполнение программы, если процессор не 32-разрядный (i286 или XT). |
2. | Произведёт поиск локального APIC в процессоре и если обнаружит его, то установит переменную db APIC_presence в 1, иначе - в 0. |
Текст этой процедуры здесь не приводится, т.к. обнаружение APIC затрагивает другие темы, которые здесь не обсуждаются - определение типа процессора и команда CPUID; по этой же причине, комментарии в самой процедуре минимальны. Исходный текст "what_cpu" заложен внутри исходника примера, который будет приведен в конце следующей главы.
Программирование контроллера прерываний также является отдельной темой, поэтому комментарии и здесь минимальны. Пока просто используйте эти "магические" действия:
1. | Процедура P_Mode_redirect_IRQ отключает APIC, по мере необходимости и перенаправляет прерывания IRQ на вектора 20h..2Fh. Далее во всех наших примерах будет использоваться такая схема распределения векторов прерываний:
00..1Fh - исключения 20h..2Fh - IRQ 30h..FFh - программные прерывания |
2. | Процедура R_Mode_redirect_IRQ используется перед возвратом в R-Mode, она восстанавливает вектора прерываний IRQ. |
3. | Процедура redirect_IRQ используется обеими вышеприведенными процедурами, её прообраз взят из BIOS-а и слегка модифицирован для наших примеров. |
4. | Процедура disable_APIC запрещает APIC для правильной работы нашего примера, enable_APIC разрешает APIC только если он был включён. |
;-------------------------------------------------------------------------- init_P_Mode_redirect_IRQ macro P_Mode_redirect_IRQ proc near cmp APIC_presence,1 jne pmrirq_1 call disable_APIC pmrirq_1: mov bx,2820h mov dx,0FFFFh call redirect_IRQ ret endp endm ;-------------------------------------------------------------------------- init_R_Mode_redirect_IRQ macro R_Mode_redirect_IRQ proc near mov bx,7008h xor dx,dx call redirect_IRQ cmp APIC_presence,1 jne rmrirq_1 call enable_APIC rmrirq_1: ret endp endm ;-------------------------------------------------------------------------- init_redirect_IRQ macro redirect_IRQ proc near ; BX = { BL = Начало для IRQ 0..7, BH = начало для IRQ 8..15 } ; DX = Маска прерываний IRQ ( DL - для IRQ 0..7, DH - IRQ 8..15 ) mov al,11h out 0a0h,al jcxz $+2 jcxz $+2 out 20h,al jcxz $+2 jcxz $+2 mov al,bh out 0a1h,al jcxz $+2 jcxz $+2 mov al,bl out 21h,al jcxz $+2 jcxz $+2 mov al,02 out 0a1h,al jcxz $+2 jcxz $+2 mov al,04 out 21h,al jcxz $+2 jcxz $+2 mov al,01 out 0a1h,al jcxz $+2 jcxz $+2 out 21h,al jcxz $+2 jcxz $+2 mov al,dh out 0a1h,al jcxz $+2 jcxz $+2 mov al,dl out 21h,al jcxz $+2 jcxz $+2 ret endp endm ;-------------------------------------------------------------------------- disable_APIC proc near ; Отключение локального APIC mov bl,0 mov ecx,1bh db 0fh, 32h ; Код команды RDMSR test ah,1000b jz dapic_end ; Если APIC был уже отключён, то сброс ; переменной APIC_presence в 0 не допустит ; разрешения APIC в процедуре ; R_Mode_redirect_IRQ. and ah,11110111b ; Сбрасываем 11-й бит в MSR 1Bh db 0fh, 30h ; Код команды WRMSR mov bl,1 dapic_end: mov APIC_presence,bl ret endp ;-------------------------------------------------------------------------- enable_APIC proc near ; Включение локального APIC mov ecx,1bh db 0fh, 32h ; Код команды RDMSR or ah,1000b ; Устанавливаем 11-й бит в MSR 1Bh db 0fh, 30h ; Код команды WRMSR ret endp ;--------------------------------------------------------------------------
Следующая глава | Оглавление | Вопросы? Замечания? Пишите: sasm@narod.ru |
Copyright © Александр Семенко. |