/* * This file deals with the Interrupt Descriptor Table. It creates a simple * IDT, with hard-coded handler functions. It is these handler functions that * can run custom handlers, registered at runtime. This file does not deal with * dispatching messages/signals to processes on an interrupt. */ #include #include #include #include #include #include #include #include "desc.h" /* Structure for an IDT Entry */ static struct IDTEntry { uint16_t offsetLower, selector; uint8_t zero, typeAttr; uint16_t offsetHigher; } __attribute__((packed)) *IDT; void (**interrupts)(struct InterruptFrame *); /* Install an IDT Entry */ static void install_idt_entry(uint8_t num, void *addr) { uint8_t type = 0x8E; /* Interrupt gate */ if (num < 32) type = 0x8F; /* Trap gate for exceptions */ if (num == 0x80) type |= 3 << 5; /* Allowed from ring 3 */ IDT[num].offsetLower = (uintptr_t) addr & 0xFFFF; IDT[num].selector = 0x08; IDT[num].zero = 0; IDT[num].typeAttr = type; IDT[num].offsetHigher = (uintptr_t) addr >> 16; } /* Generic ISR handler */ void isr_handler(struct InterruptFrame frame) { if (!interrupts[frame.intnum] && frame.intnum < 32) panic("Failed to handle exception %d (%#.8x) @ %#.8x", frame.intnum, frame.err, frame.eip); /* Send EOI */ if (frame.intnum >= 40 && frame.intnum < 48) outb(0xA0, 0x20); if (frame.intnum >= 32 && frame.intnum < 48) outb(0x20, 0x20); /* Send APIC EOI */ if (apic) LAPIC(0xB0) = 0; /* Run registered handler */ int_handler_t handler = interrupts[frame.intnum]; struct InterruptFrame *oldFrame; if (handler) { oldFrame = cpu->frame; cpu->frame = &frame; handler(&frame); cpu->frame = oldFrame; } } /* Register an exception handler */ void register_exception(uint8_t num, int_handler_t addr) { interrupts[num] = addr; } /* Register an interrupt handler */ void register_interrupt(uint8_t num, int_handler_t addr) { if (num >= 0 && num < 16) register_exception(num + 32, addr); } /* Register an IPI handler */ void register_ipi(uint8_t num, int_handler_t addr) { if (num >= 0 && num < 16) register_exception(num + 48, addr); } /* Exceptions */ extern char exc0[], exc1[], exc2[], exc3[], exc4[], exc5[], exc6[], exc7[], exc8[], exc9[], exc10[], exc11[], exc12[], exc13[], exc14[], exc15[], exc16[], exc17[], exc18[], exc19[], exc20[], exc30[]; /* Interrutps */ extern char exc32[], exc33[], exc34[], exc35[], exc36[], exc37[], exc38[], exc39[], exc40[], exc41[], exc42[], exc43[], exc44[], exc45[], exc46[], exc47[]; /* IPIs */ extern char exc48[], exc49[], exc50[], exc51[], exc52[], exc53[], exc54[], exc55[], exc56[], exc57[], exc58[], exc59[], exc60[], exc61[], exc62[], exc63[]; /* System Call */ extern char exc128[]; /* Initialise the IDT */ void init_idt(void) { IDT = (void *) alloc_frame(); /* Install exceptions */ install_idt_entry(0, exc0); install_idt_entry(1, exc1); install_idt_entry(2, exc2); install_idt_entry(3, exc3); install_idt_entry(4, exc4); install_idt_entry(5, exc5); install_idt_entry(6, exc6); install_idt_entry(7, exc7); install_idt_entry(8, exc8); install_idt_entry(9, exc9); install_idt_entry(10, exc10); install_idt_entry(11, exc11); install_idt_entry(12, exc12); install_idt_entry(13, exc13); install_idt_entry(14, exc14); install_idt_entry(15, exc15); install_idt_entry(16, exc16); install_idt_entry(17, exc17); install_idt_entry(18, exc18); install_idt_entry(19, exc19); install_idt_entry(20, exc20); install_idt_entry(30, exc30); /* Install interrupts */ install_idt_entry(32, exc32); install_idt_entry(33, exc33); install_idt_entry(34, exc34); install_idt_entry(35, exc35); install_idt_entry(36, exc36); install_idt_entry(37, exc37); install_idt_entry(38, exc38); install_idt_entry(39, exc39); install_idt_entry(40, exc40); install_idt_entry(41, exc41); install_idt_entry(42, exc42); install_idt_entry(43, exc43); install_idt_entry(44, exc44); install_idt_entry(45, exc45); install_idt_entry(46, exc46); install_idt_entry(47, exc47); /* Install IPIs */ install_idt_entry(48, exc48); install_idt_entry(49, exc49); install_idt_entry(50, exc50); install_idt_entry(51, exc51); install_idt_entry(52, exc52); install_idt_entry(53, exc53); install_idt_entry(54, exc54); install_idt_entry(55, exc55); install_idt_entry(56, exc56); install_idt_entry(57, exc57); install_idt_entry(58, exc58); install_idt_entry(59, exc59); install_idt_entry(60, exc60); install_idt_entry(61, exc61); install_idt_entry(62, exc62); install_idt_entry(63, exc63); /* Install system call handler */ install_idt_entry(128, exc128); interrupts = (void *) (IDT + 256); memset(interrupts, 0, 1024); } /* Load the IDT */ void cpu_load_idt(void) { struct DescRecord ptr = { .limit = sizeof(struct IDTEntry) * 256, .base = (uintptr_t) IDT, }; asm volatile("lidt %0" :: "m" (ptr)); }