99 lines
4.9 KiB
C
99 lines
4.9 KiB
C
#include "idt.h"
|
||
#include "string.h"
|
||
#include "../drivers/serial.h"
|
||
#include "../drivers/timer.h"
|
||
#include "../drivers/keyboard.h"
|
||
#include "../drivers/mouse.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(); extern void irq12();
|
||
|
||
// Внешняя функция на ассемблере для выполнения '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); // Клавиатура
|
||
idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); // Мышь PS/2
|
||
|
||
// Загружаем 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 if (regs.int_no == 44) {
|
||
mouse_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));
|
||
}
|