#include #include #include #include #include #include #include struct idt_entry { uint16_t base_lo; //Low part of address to jump to uint16_t sel; //Kernel segment selector uint8_t always0; uint8_t type_attr; //Type uint16_t base_hi; //High part of address to jump to } __attribute__((packed)); typedef struct idt_entry idt_entry_t; struct idt_ptr { uint16_t limit; uint32_t base; } __attribute__((packed)); typedef struct idt_ptr idt_ptr_t; #define GATE_TYPE_INTERRUPT 14 // IF is cleared on interrupt #define GATE_TYPE_TRAP 15 // IF stays as is #define GATE_PRESENT (1<<7) #define GATE_DPL_SHIFT 5 void isr0(); void isr1(); void isr2(); void isr3(); void isr4(); void isr5(); void isr6(); void isr7(); void isr8(); void isr9(); void isr10(); void isr11(); void isr12(); void isr13(); void isr14(); void isr15(); void isr16(); void isr17(); void isr18(); void isr19(); void isr20(); void isr21(); void isr22(); void isr23(); void isr24(); void isr25(); void isr26(); void isr27(); void isr28(); void isr29(); void isr30(); void isr31(); void irq0(); void irq1(); void irq2(); void irq3(); void irq4(); void irq5(); void irq6(); void irq7(); void irq8(); void irq9(); void irq10(); void irq11(); void irq12(); void irq13(); void irq14(); void irq15(); void syscall64(); // ************************************************************ // Handler code static idt_entry_t idt_entries[256]; static idt_ptr_t idt_ptr; static isr_handler_t irq_handlers[16] = {0}; static isr_handler_t ex_handlers[32] = {0}; /* Called in interrupt.s when an exception fires (interrupt 0 to 31) */ void idt_ex_handler(registers_t *regs) { if (ex_handlers[regs->int_no] != 0) { ex_handlers[regs->int_no](regs); } else { if (regs->eip >= K_HIGHHALF_ADDR) { dbg_printf("Unhandled exception in kernel code: %i\n", regs->int_no); dbg_dump_registers(regs); PANIC("Unhandled exception"); } else { ASSERT(current_thread != 0 && current_thread->user_ex_handler != 0); current_thread->user_ex_handler(regs); } } // maybe exit if (current_thread != 0 && regs->eip < K_HIGHHALF_ADDR && current_thread->must_exit) { exit(); } } /* Called in interrupt.s when an IRQ fires (interrupt 32 to 47) */ void idt_irq_handler(registers_t *regs) { int st = enter_critical(CL_EXCL); // if someone tries to yield(), an assert will fail if (regs->err_code > 7) { outb(0xA0, 0x20); } outb(0x20, 0x20); if (regs->err_code == 0) { irq0_handler(regs, st); } else { dbg_printf("irq%d.", regs->err_code); if (irq_handlers[regs->err_code] != 0) { irq_handlers[regs->err_code](regs); } exit_critical(st); } // maybe exit if (current_thread != 0 && regs->eip < K_HIGHHALF_ADDR && current_thread->must_exit) { exit(); } } /* Caled in interrupt.s when a syscall is called */ void idt_syscall_handler(registers_t *regs) { syscall_handler(regs); // maybe exit if (current_thread != 0 && regs->eip < K_HIGHHALF_ADDR && current_thread->must_exit) { exit(); } } /* For internal use only. Sets up an entry of the IDT with given parameters. */ static void idt_set_gate(uint8_t num, void (*fun)(), uint8_t type) { uint32_t base = (uint32_t)fun; idt_entries[num].base_lo = base & 0xFFFF; idt_entries[num].base_hi = (base >> 16) & 0xFFFF; idt_entries[num].sel = K_CODE_SEGMENT; idt_entries[num].always0 = 0; idt_entries[num].type_attr = GATE_PRESENT | (3 << GATE_DPL_SHIFT) // accessible from user mode | type; } static const struct { uint8_t num; void (*fun)(); uint8_t type; } gates[] = { // Most processor exceptions are traps and handling them // should be preemptible { 0, isr0, GATE_TYPE_TRAP }, { 1, isr1, GATE_TYPE_TRAP }, { 2, isr2, GATE_TYPE_TRAP }, { 3, isr3, GATE_TYPE_TRAP }, { 4, isr4, GATE_TYPE_TRAP }, { 5, isr5, GATE_TYPE_TRAP }, { 6, isr6, GATE_TYPE_TRAP }, { 7, isr7, GATE_TYPE_TRAP }, { 8, isr8, GATE_TYPE_TRAP }, { 9, isr9, GATE_TYPE_TRAP }, { 10, isr10, GATE_TYPE_TRAP }, { 11, isr11, GATE_TYPE_TRAP }, { 12, isr12, GATE_TYPE_TRAP }, { 13, isr13, GATE_TYPE_TRAP }, { 14, isr14, GATE_TYPE_INTERRUPT }, // reenables interrupts later on { 15, isr15, GATE_TYPE_TRAP }, { 16, isr16, GATE_TYPE_TRAP }, { 17, isr17, GATE_TYPE_TRAP }, { 18, isr18, GATE_TYPE_TRAP }, { 19, isr19, GATE_TYPE_TRAP }, { 20, isr20, GATE_TYPE_TRAP }, { 21, isr21, GATE_TYPE_TRAP }, { 22, isr22, GATE_TYPE_TRAP }, { 23, isr23, GATE_TYPE_TRAP }, { 24, isr24, GATE_TYPE_TRAP }, { 25, isr25, GATE_TYPE_TRAP }, { 26, isr26, GATE_TYPE_TRAP }, { 27, isr27, GATE_TYPE_TRAP }, { 28, isr28, GATE_TYPE_TRAP }, { 29, isr29, GATE_TYPE_TRAP }, { 30, isr30, GATE_TYPE_TRAP }, { 31, isr31, GATE_TYPE_TRAP }, // IRQs are not preemptible ; an IRQ handler should do the bare minimum // (communication with the hardware), and then pass a message to a worker // process in order to do further processing { 32, irq0, GATE_TYPE_INTERRUPT }, { 33, irq1, GATE_TYPE_INTERRUPT }, { 34, irq2, GATE_TYPE_INTERRUPT }, { 35, irq3, GATE_TYPE_INTERRUPT }, { 36, irq4, GATE_TYPE_INTERRUPT }, { 37, irq5, GATE_TYPE_INTERRUPT }, { 38, irq6, GATE_TYPE_INTERRUPT }, { 39, irq7, GATE_TYPE_INTERRUPT }, { 40, irq8, GATE_TYPE_INTERRUPT }, { 41, irq9, GATE_TYPE_INTERRUPT }, { 42, irq10, GATE_TYPE_INTERRUPT }, { 43, irq11, GATE_TYPE_INTERRUPT }, { 44, irq12, GATE_TYPE_INTERRUPT }, { 45, irq13, GATE_TYPE_INTERRUPT }, { 46, irq14, GATE_TYPE_INTERRUPT }, { 47, irq15, GATE_TYPE_INTERRUPT }, // Of course, syscalls are preemptible { 64, syscall64, GATE_TYPE_TRAP }, { 0, 0, 0 } }; /* Remaps the IRQs. Sets up the IDT. */ void idt_init() { memset((uint8_t*)&idt_entries, 0, sizeof(idt_entry_t) * 256); //Remap the IRQ table outb(0x20, 0x11); outb(0xA0, 0x11); outb(0x21, 0x20); outb(0xA1, 0x28); outb(0x21, 0x04); outb(0xA1, 0x02); outb(0x21, 0x01); outb(0xA1, 0x01); outb(0x21, 0x0); outb(0xA1, 0x0); for (int i = 0; gates[i].type != 0; i++) { idt_set_gate(gates[i].num, gates[i].fun, gates[i].type); } idt_ptr.limit = (sizeof(idt_entry_t) * 256) - 1; idt_ptr.base = (uint32_t)&idt_entries; asm volatile ("lidt %0"::"m"(idt_ptr):"memory"); // Some setup calls that come later on are not preemptible, // so we wait until then to enable interrupts. } /* Sets up an IRQ handler for given IRQ. */ void idt_set_irq_handler(int number, isr_handler_t func) { if (number < 16 && number >= 0) { irq_handlers[number] = func; } } /* Sets up a handler for a processor exception */ void idt_set_ex_handler(int number, isr_handler_t func) { if (number >= 0 && number < 32) { ex_handlers[number] = func; } } void dbg_dump_registers(registers_t *regs) { dbg_printf("/ Exception %i\n", regs->int_no); dbg_printf("| EAX: 0x%p EBX: 0x%p ECX: 0x%p EDX: 0x%p\n", regs->eax, regs->ebx, regs->ecx, regs->edx); dbg_printf("| EDI: 0x%p ESI: 0x%p ESP: 0x%p EBP: 0x%p\n", regs->edi, regs->esi, regs->esp, regs->ebp); dbg_printf("| EIP: 0x%p CS : 0x%p DS : 0x%p SS : 0x%p\n", regs->eip, regs->cs, regs->ds, regs->ss); dbg_printf("| EFl: 0x%p I# : 0x%p Err: 0x%p\n", regs->eflags, regs->int_no, regs->err_code); dbg_printf("- Stack trace:\n"); uint32_t ebp = regs->ebp, eip = regs->eip; int i = 0; while (ebp >= K_HIGHHALF_ADDR && eip >= K_HIGHHALF_ADDR && i++ < 10) { dbg_printf("| 0x%p EIP: 0x%p\n", ebp, eip); uint32_t *d = (uint32_t*)ebp; ebp = d[0]; eip = d[1]; } dbg_printf("\\\n"); } /* vim: set ts=4 sw=4 tw=0 noet :*/