#include "interrupts.h" #include "kernel.h" #include "log.h" #include "e1000.h" #include "asm_int.h" #include "asm_pit.h" #include "driver/mouse.h" #include "driver/keyboard.h" #include "scheduler.h" #include "asm_x86.h" #include "smp.h" #include "apic.h" #include "ringbuffer.h" #include "compositor.h" /** The size of our interrupts table */ #define INT_MAX 256 // 0-255 /** Addresses of the registered interrupt handlers */ static uint32_t handlers[INT_MAX]; /** The interrupt descriptor table */ struct int_desc { uint16_t addrLo; uint16_t sel; uint8_t zeros; uint8_t flags; uint16_t addrHi; } idt[INT_MAX]; /** The interrupt descriptor table descriptor */ struct idt_desc { uint16_t size; uint16_t baseLo; uint16_t baseHi; } idtd; /** Sets a handler for a specific interrupt */ static void int_install_ir(int irq, uint16_t flags, uint16_t sel, void *addr) { uint64_t base=(uint32_t)&(*(uint32_t*)addr); idt[irq].addrLo = base & 0xffff; idt[irq].addrHi = (base >> 16) & 0xffff; idt[irq].zeros=0; idt[irq].flags=flags; idt[irq].sel=sel; } /** register an interrupt handler for given irq number */ void interrupt_register(uint32_t irq, uint32_t func_addr) { if(irq<128||irq>160)kpanic("irq number out of range!"); if(handlers[irq]!=0)kpanic("handler already registered!"); handlers[irq]=func_addr; } /* * Interrupt dispatcher * Remeber that we are inside an interrupt here! */ uint32_t interrupt_handler(uint32_t esp, uint32_t irq) { uint32_t cpu=smp_get(SMP_APIC_ID); if(handlers[irq]!=0) { uint32_t (*f)(uint32_t esp)=handlers[irq]; esp=f(esp); scheduler_wake_worker(esp); apic_eoi(); esp=scheduler_run(esp,-1); return esp; } if(irq==INTERRUPT_APIC_TIMER) { if(cpu==0) { compositor_wake2(); scheduler_wake_all(); scheduler_wake_worker(esp); } } if(irq==INTERRUPT_APIC_TIMER || irq==INTERRUPT_IPI) { esp=scheduler_run(esp,-1); apic_eoi(); return esp; } if(irq==INTERRUPT_SYSCALL) // do not EOI { uint32_t *stack; stack=esp; task_syscall(stack[11],stack[8],stack[10],stack[9]); //eax,ebx,ecx,edx scheduler_wake_worker(esp); esp=scheduler_run(esp,-1); return esp; } kpanic("unhandled interrupt %d",irq); /* if(handlers[irq]!=0) { //uint32_t (*f)(uint32_t esp)=handlers[irq]; //esp=f(esp); apic_eoi(); } else if(irq!=INTERRUPT_SYSCALL&&irq!=INTERRUPT_IPI&&irq!=INTERRUPT_APIC_TIMER) { kpanic("unhandled interrupt %d",irq); } // process IRQ switch(irq) { case INTERRUPT_SYSCALL: stack=esp; // task_syscall(stack[11],stack[8],stack[10],stack[9]); //eax,ebx,ecx,edx break; case INTERRUPT_APIC_TIMER: // frequency is configured in smp.c (100hz) esp=scheduler_run(esp,-1); apic_eoi(); break; case INTERRUPT_IPI: // inter process interrupt esp=scheduler_run(esp,-1); apic_eoi(); break; case 255: // default or spurious kpanic("Spurious/Unknown Interrupt!?"); break; } // reschedule to kernel worker on these if(irq==INTERRUPT_SYSCALL||irq==INTERRUPT_KEYBOARD||irq==INTERRUPT_MOUSE) { // scheduler_wake_worker(esp); esp=scheduler_run(esp,-1); } // Ack all to LAPIC, except software syscalls return esp; */ } /** * init interrupt descriptor table (TODO; do we seriously have to hardcode this?) */ void interrupts_init() { klog("Initializing. IDT: 0x%08x, IDTD: 0x%08X",&idt,&idtd); // Default interrupt handling for(int i=0; i>16; idtd.baseLo=0xffff&addr; __asm__("lidt %0"::"m" (idtd)); }