понеділок, 13 червня 2011 р.

IRQ та PIC

Фрагмент 5-го уроку захищеного режиму, вартий уваги сам по собі. Інформація місцями не до кінця перевірена, багато що опущено, так як не має відношення до типової архітектури x86, але може комусь згодиться :-)

IRQ та PIC

Про зовнішні події процесор отримує інформацію за допомогою переривань. Переривання асинхронні по своїй природі. До прикладу це може бути переривання від диску, що закінчив операцію або від таймера про закінчення чергового інтервалу часу. "Керує" зовнішніми перериваннями та передає їх процесору спеціальний пристрій. В архітектурі IBM-PC сумісних комп'ютерів це був програмований контролер переривань (Programmable Interrupt Controllers, PIC) Intel 8259. Хоча з виникнення сімейства в 1981 минуло вже три десятиліття та навіть на x86-сумісних платформах існують багато досконаліших технологій роботи з перериваннями, таких як APIC (Advanced PIC, див. наприклад http://wiki.osdev.org/APIC), однак для забезпечення зворотної сумісності програмні способи роботи з контролером переривань епохи Intel 8259 тим чи іншим чином підтримуються. А потреба перепрограмовувати його при роботі з захищеним режимом є. Навіщо - стане зрозумілим далі.

Так як переривання можуть надходити від різних джерел, однією з функції PIC є їх мультиплексування та послідовне передання процесору згідно пріоритетів. Запити на переривання - Interrupt requests (IRQs) приходить на один з входів PIC, він перевіряє чи переривання не замасковане, і чи немає ще необроблених переривань з вищим приорітетом. Якщо відповідно не замасковано і немає більш приорітетних - переривання передається процесору1. Перші моделі (IBM PC та XT) мали один PIC, що може обслуговувати максимум 8 ліній IRQ. Це досить мало, тому починаючи з AT використовується два PIC, з'єднаних каскадно. Головний, Master PIC, під'єднано безпосередньо до процесора та обслуговує IRQ з номерами 0,1, 3-7, а вторинний, Slave PIC - до лінії IRQ2 головного2 та обслуговує IRQ 8-15. Тобто, якщо виникають IRQ з номером 8 та більше то воно викличе IRQ2 головного PIC, який і передасть його процесору. Тут теж є ряд тонкощів, у які ми не заглиблюватимемося3, але разом вони можуть обслуговувати до 15 ліній переривань.

Вся ця інформація, на жаль, потрібна тому що розробники IBM PC не прислухалися до розробників процесора Intel 8086/88 та під IRQ0-IRQ7 використали номери переривань процесора, зарезервовані для внутрішнього використання: int 08h - int 0Fh. Тому в захищеному режимі переривання таймера (IRQ0) викличе обробник int 08h (Double Fault!), що явно нас не влаштовує. Щоб виправити ситуацію доведеться перепрограмовувати PIC4 (а при поверненні в реальний режим повертати все назад).

Відповідність між IRQ та перериваннями по замовчуванню така:

Лінія Переривання Функція
Master PIC
IRQ0 int 08h Системний таймер
IRQ1 int 09h Контролер клавіатури
IRQ2 int 0Ah Служить для зв'язку з Slave PIC. Апаратні перенаправляються на IRQ9
IRQ3 int 0Bh COM2 (разом з COM4, якщо він присутній)
IRQ4 int 0Ch COM1 (разом з COM3, якщо він присутній)
IRQ5 int 0Dh LPT2/звукова карта/доступне іншій периферії
IRQ6 int 0Eh контролер гнучких дисків
IRQ7 int 0Fh LPT1/звукова карта/доступне іншій периферії
Slave PIC
IRQ8 int 70h CMOS RTC таймер
IRQ9 int 71h Доступне/SCSI/викликається при "появі" IRQ2
IRQ10int 72h Доступне/SCSI/мережева карта
IRQ11int 73h Доступне/SCSI/мережева карта
IRQ12int 74h Мишка
IRQ13int 75h Математичний сопроцесор (FPU) або міжпроцесорне переривання (inter-processor interrupt, IPI)
IRQ14int 76h Головний канал IDE (ATA)
IRQ15int 77h Вторинний канал IDE (ATA)


З таблиці видно, що PIC використовує послідовні номери переривань для обробки IRQ, які він обслуговує. Номер, з якого починати, ми можемо запрограмувати. Цей номер має бути кратним 8, так як молодших три біти використовуються для вибору номеру переривання конкретного IRQ.

Робота з PIC здійснюється за допомогою командних слів (Operation Command Word - OCW та Initialization Control Word - ICW), які виводяться у відповідні порти. Кожен з PIC має два порти - порт команди та порт даних. Запис в командний порт передає команду, читання - повертає статус PIC. Читання порту даних повертає маску переривань (регістр IMR, див. нижче), запис в нього її змінює.

Порт
Master PIC - команди 0x20
Master PIC - дані 0x21
Slave PIC - команди 0xA0
Slave PIC - дані 0xA1


PIC має три регістри:

  • Interrupt Mask Register (IMR) - регістр маскування запитів на переривання, показує які рівні IRQ зараз заблоковані.
  • Interrupt Request Register (IRR) - регістр запитів на переривання, описує які переривання зараз очікують підтвердження.
  • In-Service Register (ISR) - регістр перериваннь, що обробляються, описує які переривання зараз обробляються і вимагатимуть команди про завершення переривання (EOI — End Of Interrupt)5.

Для перепрограмування відображення переривань слід передати ICW1 для ініціалізації та потім послідовність з трьох командних слів6:

  • ICW2 - зсув вектора (переривань),
  • ICW3 - зв'язок між головним та вторинним,
  • ICW4 - додаткова інформація про середовище.
Формат їх детально тут не описуватиметься, за додатковою інформацією можна звертатися до офіційного мануала 8259  http://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf, "Operating Systems Development - PIC, PIT, and exceptions by Mike,

Важливі для нас біти ICW1:
  • біт 0 - чи потрібне ICW4
  • біт 4 - запит на ініціалізацію
  • решта - в більшості випадків для архітектури x86 нульові.

Важливі для нас біти ICW2:
  • біти 0-2 - 0
  • біти 3-7 - початковий номер переривання для цього PIC
ICW3 - вказує яке IRQ використовується для зв'язку головного з вторинним PIC. Для головного єдиний біт, що дорівнює 1, вказує яке IRQ використано для взаємодії з вторинним. Тобто, типовому для IBM-PC IRQ2 відповідає 0x100b = 0x4h = 1<<2. Для вторинного біти 0-2 містять номер IRQ гловного, що використовується, решта мають бути нуль. Тобто IRQ2 відповідатиме 0x2h7.

Важливі для нас біти ICW4:
  • біт 0 - 1 якщо працюємо з x86. Для нас - завжди.
  • біт 1 - 1 відповідає Auto EOI, зазвичай має бути нульовим.
  • решта - в більшості випадків для архітектури x86 нульові.
Разом роботу цієї машинерії продемонструємо на прикладі задачі, яку нам ставить дефект архітекури IBM PC, перепрограмування векторів переривань:

#define PIC1        0x20         /* базова адреса порта головного PIC */
#define PIC2        0xA0         /* базова адреса порта вторинного PIC */
#define PIC1_COMMAND    PIC1
#define PIC1_DATA   (PIC1+1)
#define PIC2_COMMAND    PIC2
#define PIC2_DATA   (PIC2+1)

#define ICW1_ICW4   0x01        /* Біт 0, чи потрібен ICW4  */
#define ICW1_INIT   0x10        /* Біт запиту на ініціалізацію */

#define ICW4_8086   0x01        /* Режим 8086/88 (проти MCS-80/85)*/


/*Пересилаємо ICW1 */
outportb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); /*Запит на ініціалізацію/
outportb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);

/*Пересилаємо ICW2 --- Початковий вектор переривання */
outportb(PIC1_DATA, new_PIC1_interrupt_offset);
outportb(PIC2_DATA, new_PIC2_interrupt_offset);

/*Пересилаємо ICW3 --- взаємодія головного і вторинного PIC*/
outportb(PIC1_DATA, 0x04);/*0x100b - IRQ2, як її хоче головний*/
outportb(PIC2_DATA, 0x02);/*просто 2 - IRQ2, як її хоче вторинний*/

/*Пересилаємо ICW4 --- вмикаємо режим x86*/
outportb(PIC1_DATA, ICW4_8086);
outportb(PIC1_DATA, ICW4_8086);

Після кожної команди PIC можна вставити невелику затримку на час реакції. На сучасних комп'ютерах вона часто не потрібна, однак її відсутність може служити джерелом тонких збоїв у роботі.

Щоб передати сигнал неспецифічну команду EOI використовується OCW2. Його формат:
  • біти 0-2 - рівень активного IRQ.
  • біти 3-4 - 0
  • біт 5 - EOI
  • біти 6 і 7 - команди Selection i Rotation, ми їх не розглядатимемо.
Здійснюється її передача очевидним чином:

#define PIC_EOI     0x20 /*Тільки 5-й біт 20h дорівнює 1*/

outportb(PIC1_COMMAND, PIC_EOI);

Якщо переривання прийшло від вторинного контролера, то головний теж слід повідомити про завершення обробки переривання у підлеглого:

#define PIC_EOI     0x20 /*Тільки 5-й біт 20h дорівнює 1*/

void PIC_sendEOI(unsigned char irq) {
    if(irq >= 8)
        outportb(PIC2_COMMAND,PIC_EOI);

    outportb(PIC1_COMMAND,PIC_EOI);
}

Для маскування переривань використовується OCW1. Це - байт, кожен біт якого відповідає IRQ з відповідним номером. Щоб замаскувати IRQ номер maskIRQline8:

uint16_t port;
uint8_t value;

if(IRQline < 8) {
    port = PIC1_DATA;
} else {
    port = PIC2_DATA;
    IRQline -= 8;
}
value = inb(port) & ~(1 << IRQline);
outportb(port, value);


Всі переривання можна замаскувати так:

outportb(PIC1_DATA, 0FFh);
outportb(PIC2_DATA, 0FFh);


Footnotes:


1Тут є ряд тонкощів, у які не хотілося б заглиблюватися. Наприклад, коли є переривання, що очікує обробки, PIC повідомляє про це процесор. При цьому йому передається фальшивий номер IRQ з найменшим приорітетом. Процесор підтверджує та очікує справжній номер переривання, який і передається на наступному етапі. Ця здавалося б дрібна тонкість приводить до того що за певних умов між першим та другим етапом переривання може зникнути. Наприклад через передчасний сигнал EOI (End of interrupt), описаний нижче. В результаті виникають так-звані фальшиві переривання. Боротися з ними можна, перевіряючи відповідний біт регістра ISR (In Service Register) PIC. Детальніше - див. http://wiki.osdev.org/PIC/Spurious_IRQs
2Тому трішки раніше номер 2 був пропущений.
3Наприклад, IRQ2, яке прийшло по зовнішній лінії (а не від Slave PIC) відображається на IRQ9.
Детальніше про цю плутану архітектуру див. http://www.osdever.net/tutorials/view/irqs
4В деяких підручниках рекомендують замість перепрограмування PIC в обробнику переривання аналізувати яке його походження - від PIC чи від процесора. Таке рішення є неелегантним, приводить до переускладнених обробників і його хоча б теоретична працезадтінсть неочевидна. Не робіть так!
5Буває специфічна, неспецифічна та автоматична. Специфічна вказує на переривання, обробка якого завершена, фактично - який біт обнулити в ISR, неспецифічна EOI завершує переривання з найвищим приорітетом з активних. Автоматичний скидує біти в ISR зразу після підтвердження
переривання. Драйвери у Windows та DOS типово використовують неспецифічну EOI.
6Передавати їх слід обов'язково, ICW1 без решти приведе до невизначеної поведіки.
7Просто, правда?...


Translated from TEX by  TTHgold, version 4.00.

Немає коментарів:

Дописати коментар