#include "kernel/kernel.h" #include "asm_int.h" #include "asm_pit.h" #include "driver/mouse.h" #include "driver/keyboard.h" #include "interrupts.h" #include "scheduler.h" #include "asm_x86.h" #include "smp.h" /** The size of our interrupts table */ #define INT_MAX 256 // 0-255 /** The interrupt descriptor table */ static 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 */ static 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; } /** Installs the interrupt table */ void interrupts_install() { idtd.size=sizeof(struct int_desc)*INT_MAX; uint32_t addr=(uint32_t)&idt[0]; idtd.baseHi=addr>>16; idtd.baseLo=0xffff&addr; __asm__("lidt %0"::"m" (idtd)); } /* * Interrupt dispatcher * * Remeber that we are inside an interrupt here! * */ uint32_t interrupt_handler(uint32_t esp, uint32_t irq) { // DO NOT WRITE INSIDE INTERRUPTS!! COZ IT ACQUIRES LOCK AND WE WILL DEADLOCK // klog("int: %d on 0x%x",irq,apicID()); if(irq==INTERRUPT_PIT_TIMER)asm_pit_tick(); // mouse and kb if(irq==INTERRUPT_KEYBOARD || irq==INTERRUPT_MOUSE){ uint32_t in=x86_inb(0x60); if(irq==INTERRUPT_KEYBOARD)keyboard_handle(in); // do this in separate thread! // TODO: mouse // test ipi //apicIPI(15,0x81); // force cpu16 to autoschedule? just test //klog("0x60 in %d",in); } // 0x80 - a syscall is coming in if(irq==INTERRUPT_SYSCALL){ uint32_t *stack=esp; uint32_t eax=stack[11]; uint32_t ebx=stack[8]; uint32_t ecx=stack[10]; uint32_t edx=stack[9]; // klog("syscall: %d (ebx=0x%08X,ecx=0x%08X,edx=0x%08X)",eax,ebx,ecx,edx); task_syscall(eax,ebx,ecx,edx); esp=my_scheduler(esp,2); // force scheduling of pid=2 (kernel worker) } // schedules on APIC timer 0x8C and IPI 0x81 if(irq==INTERRUPT_PIT_TIMER || irq==INTERRUPT_IPI)esp=my_scheduler(esp,-1); // autoschedule if(irq!=INTERRUPT_SYSCALL)apicEOI(); // ack all except software syscalls if(irq==255)kpanic("Spurious/Unknown Interrupt!?"); // default and spurious return esp; } // log helpers // void errlog(uint32_t error_code) { klog("error_code: 0x%08X",error_code); } void defklog(uint32_t esp) { klog("EXCEPTION: eip: 0x%08X",*(uint32_t *)esp); esp+=4; klog("EXCEPTION: segment: 0x%08X",*(uint16_t *)esp); esp+=4; klog("EXCPETION: eflags: 0x%08X",*(uint32_t *)esp); } void show_selector_error(uint32_t err) { klog("Selector Error Details:"); klog("External Event: %x",err&0b1); klog("Location: 0x%x (0-GDT/1-IDT/2-LDT/3-IDT)",err&0b110); klog("Selector: 0x%x",err&0b1111111111111000); } void show_page_fault_error(uint32_t error_code) { klog("Page Fault Error Details:"); klog("error_code_P (Present): %d",error_code&1?1:0); klog("error_code_W/R (Write): %d",error_code&2?1:0); klog("error_code_U/S (User): %d",error_code&4?1:0); klog("error_code_RSVD (Reserved Write) : %d",error_code&8?1:0); klog("error_code_I/D (Instruction Fetch): %d",error_code&16?1:0); klog("at addr: 0x%08X",x86_get_cr(2)); } void exception_handle(uint32_t esp, uint32_t irq) { uint32_t error_code=0; klog("EXCEPTION: apicID: 0x%08X",apicID()); klog("EXCEPTION: vector nr.: %d",irq); switch(irq){ //this interrupts push also an error_code case 8: case 10: case 11: case 12: case 13: case 14: case 17: case 30: error_code = *(uint32_t *)esp; esp+=4; } klog("EXCEPTION: error_code: %d",irq); defklog(esp); switch(irq){ case 0: kpanic("Divide by 0"); case 1: kpanic("Single step (debugger)"); case 2: kpanic("Non Maskable Interrupt"); case 3: kpanic("Breakpoint (debugger)"); case 4: kpanic("Overflow"); case 5: kpanic("Bounds check"); case 6: kpanic("Undefined OP Code"); case 7: kpanic("No coprocessor"); case 8: kpanic("Double Fault"); case 9: kpanic("Coprocessor Segment Overrun"); case 10: show_selector_error(error_code); kpanic("Invalid TSS"); case 11: show_selector_error(error_code); kpanic("Segment Not Present"); case 12: show_selector_error(error_code); kpanic("Stack Segment Overrun"); case 13: show_selector_error(error_code); kpanic("Exception: Fault: General Protection Fault"); case 14: show_page_fault_error(error_code); kpanic("Exception: Fault: Page Fault"); case 15: kpanic("RESERVED"); case 16: kpanic("Coprocessor error"); case 17: kpanic("Alignment Check"); case 18: kpanic("Machine Check"); } } // set default handler for all interrupts for a start void interrupts_init(uint16_t sel) { klog("initializing. IDT: 0x%08x, IDTD: 0x%08X",&idt,&idtd); // Default interrupt handling for(int i=0; i