#include "idt.h" #include "string.h" #include "../drivers/serial.h" #include "../drivers/timer.h" #include "../drivers/keyboard.h" // Сам массив IDT на 256 векторов и указатель на него struct idt_entry idt[256]; struct idt_ptr idtp; // Процессорные исключения (0-21) extern void isr0(); extern void isr1(); extern void isr2(); extern void isr3(); extern void isr4(); extern void isr5(); extern void isr6(); extern void isr7(); extern void isr8(); extern void isr9(); extern void isr10(); extern void isr11(); extern void isr12(); extern void isr13(); extern void isr14(); extern void isr15(); extern void isr16(); extern void isr17(); extern void isr18(); extern void isr19(); extern void isr20(); extern void isr21(); // Аппаратные прерывания железа (IRQ) extern void irq0(); extern void irq1(); // Внешняя функция на ассемблере для выполнения 'lidt' extern void idt_load(); // Заполнение полей одного дескриптора void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { idt[num].base_low = (base & 0xFFFF); idt[num].base_high = ((base >> 16) & 0xFFFF); idt[num].sel = sel; idt[num].always0 = 0; idt[num].flags = flags; } // Главная функция инициализации IDT void idt_init(void) { // Настраиваем указатель IDTR idtp.limit = (sizeof(struct idt_entry) * 256) - 1; idtp.base = (uint32_t)&idt; // Зануляем всю таблицу перед использованием for (int i = 0; i < 256; i++) { idt_set_gate(i, 0, 0, 0); } // 0x08 — Селектор сегмента кода ядра // 0x8E — Флаги: Present, Ring 0, 32-bit Interrupt Gate // Пихаем исключения процессора в IDT idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E); idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E); idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E); idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E); idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E); idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E); idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E); idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E); idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E); idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E); idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E); idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E); idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E); idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E); idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E); idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E); idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E); idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E); idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E); idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E); idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E); idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E); // Вешаем аппаратные прерывания (после перемапливания PIC они будут тут) idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); // Таймер PIT idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); // Клавиатура // Загружаем IDTR в процессор idt_load(); } // Сюда сходятся все исключения процессора (0-31) void isr_handler(struct registers regs) { // Пока у нас нет printf, тут будет пусто или заглушка для отладки. // Когда процессор словит ошибку (например деление на 0), он вызовет эту функцию. for(;;); } // Сюда сходятся все прерывания от железа (32-47) void irq_handler(struct registers regs) { if (regs.int_no == 32) { timer_handler(); } else if (regs.int_no == 33) { keyboard_handler(); // <-- Вызываем обработчик клавиатуры при векторе 33 } else { char irq_str[4]; itoa(regs.int_no, irq_str, 10); kprint_serial("got unknown IRQ "); kprint_serial(irq_str); kprint_serial("\n"); } // Если прерывание пришло от чипа PIC2 (IRQ 8-15, векторы 40-47), шлем ему EOI (End of Interrupt) if (regs.int_no >= 40) { __asm__ __volatile__("outb %%al, %%dx" :: "a"(0x20), "d"(0xA0)); } // В любом случае шлем EOI главному чипу PIC1 (порты 0x20/0x20) __asm__ __volatile__("outb %%al, %%dx" :: "a"(0x20), "d"(0x20)); }