peredOS/kernel/idt.c

95 lines
4.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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));
}